Templated class specialization where template argument is a template
It's possible to specialize the class like this
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t) { /* something */ }
};
It's not possible to specialize just the member method, because the specialization is on the class as a whole, and you have to define a new class. You can, however, do
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t);
};
template <>
template <typename T,typename S>
void MyTemplateClass<SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S>& t)
{
// something
}
to split up the declaration and definition.
C++ - specialize function template on a templated class with a non type template parameter
Partial template specializations are not allowed for function templates.
Use SFINAE or class templates
template <class T>
struct validateType : std::false_type {};
template <class A, A val, class B>
struct validateType<Foo<A, val, B>> : std::true_type {};
Edit:
Is this supposed to work for template functions as well?
NO. Partial template specializations are not allowed for function templates.
for template function, use SFINAE.
For example, this sample check weather T is unsigned integer type(C++17).
template<typename T, std::enable_if_t<std::is_unsigned_v<T>, std::nullptr_t> = nullptr>
T foo(T n);
std::is_unsigned_v
was added in C++17. before C++17, usestd::is_unsigned<T>::value
.
https://en.cppreference.com/w/cpp/types/is_unsignedstd::enable_if_t
was added in C++14. before C++14, usetypename std::enable_if<con, T>::type
.
https://en.cppreference.com/w/cpp/types/enable_ifstd::nullptr_t
can hole only one value(nullptr
) so that I use it for SFINAE enabler.
(ja) https://qiita.com/kazatsuyu/items/203584ef4cb8b9e52462
However, in your case, you chould use class templates. It's simplest way to use class templates to check wether T is template class foo(BTW, not for template class foo, std::is_same
is simplest way).
How to specialize a class template with a template template parameter?
The following code compiles fine:
#include <type_traits>
template <typename T>
struct X {};
// primary template, no template template parameter
template<typename T>
struct Z : std::false_type {};
// specialization on the template template parameter with arbitrary T
template<typename T>
struct Z<X<T>> : std::true_type {};
// here's where you need the template template parameter
template <template<class> class C>
struct Z<C<int>> : std::true_type {};
int main()
{
static_assert(!Z<Z<double>>::value, "" );
static_assert( Z<Z<int >>::value, "" );
static_assert( Z<X<double>>::value, "" );
// static_assert( Z<X<int >>::value, "" ); // error: ambiguous
// partial specialization
}
In your code you give Z
a template template parameter, even though that should be done for the specialization only. That's why your code does not compile.
Template member function specialization of a templated class without specifying the class template parameter
You can use a technique called tag dispatch and replace the template specialisations by function overloads.
template<typename>
struct Tag {};
template <class A>
struct C3
{
void f_impl(Tag<int>) const;
void f_impl(Tag<char>) const;
template<class B>
void f() const {
f_impl(Tag<B>{});
}
};
struct D { static int g(void){ return 999; } };
template <class A>
void C3<A>::f_impl(Tag<int>) const { std::cout<<A::g()+1<<std::endl; }
template <class A>
void C3<A>::f_impl(Tag<char>) const { std::cout<<A::g()+2<<std::endl; }
Then your call site looks exactly as you want:
C3<D> c3; c3.f<int>(); // expect to see 1000
C3<D> c4; c4.f<char>(); // expect to see 1001
Full example here.
Template Specialisation with Template Argument
For C++11 you can SFINAE enable/disable (using std::enable_if
) two differents versions of foo()
inside a not specialized Foo
class.
In C++98 you don't have Sorry: my idea doesn't works because this method require the use of default template arguments for methods that is a C++11 innovation.std::enable_if
but you can simulate it (give me some minutes and I try to propose an example).
Another way is define a template base class for Foo()
, say FooBase
, insert foo()
(and only foo()
) in FooBase
and specialize FooBase
.
Another way, that works also with C++98, can be tag dispatching: you can define an unique foo()
, with zero parameter, that call another foo()
, with a parameter that is determined by T
.
The following is a full (C++98 compilable) example
#include <iostream>
struct barWay {};
struct noBarWay {};
template <int>
struct Bar
{ };
template <typename>
struct selectType
{ typedef noBarWay type; };
template <int N>
struct selectType< Bar<N> >
{ typedef barWay type; };
template <typename T>
struct Foo
{
void foo (noBarWay const &)
{ std::cout << "not Bar version" << std::endl; }
void foo (barWay const &)
{ std::cout << "Bar version" << std::endl; }
void foo ()
{ foo(typename selectType<T>::type()); }
};
int main ()
{
Foo<int> fi;
Foo< Bar<42> > fb;
fi.foo();
fb.foo();
}
Templated function template specialization
A partial specialization is when you specify part of the type of the template, but not the whole thing. For example,
template <>
template<class T> set<T> convertTo<set<T>>(const char* str)
would partially specialize for set<T>
if partial function specialization were allowed.
The two main ways of handling this are to instead overload, by removing the template<>
part, or better yet switch to using template class specialization. The problem with overloading is that it looks somewhat different if you are overloading with another template (as with set<T>
) or with a single type (as with int
), and mixing specialization and overload almost certainly doesn't work as you expect.
Therefore, template class specialization is usually the best way to go, and can be done like this:
// Generic version
template <typename T>
class Converter {
public:
T operator() (const char* str) {
T output;
stringstream ss(str, stringstream::in);
ss >> output;
return output;
}
};
template <>
class Converter<int> {
public:
int operator() (const char* str) {
return atoi(str);
}
};
// ...
template <typename T>
T convertTo(const char* str) {
return Converter<T>{}(str);
}
That way you can use any type of specialization you want for the class without issue.
Specialize template class constructor on templated template parameter
A C++11 solution could be based on SFINAE: enabling the first or the second constructor if U
is a S
based type or not.
To make this, can be useful develop a type traits to detect if a type is (or isn't) S
based; by example
template <typename>
struct isS : public std::false_type
{ };
template <typename T>
struct isS<S<T>> : public std::true_type
{ };
With isS
, you can write your constructors (in the body of the A
class) as follows
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
If you need the template argument of S
, you can define the specialization of isS
as follows
template <typename T>
struct isS<S<T>> : public std::true_type
{ using type = T; };
and use it as typename isS<V>::type
.
A full working example
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
struct S
{
S (T const &, bool, bool)
{ std::cout << "S constructor" << std::endl; }
};
template <typename>
struct isS : public std::false_type
{ };
template <typename T>
struct isS<S<T>> : public std::true_type
{ };
template <typename T, typename U>
struct A : public U
{
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
};
int main ()
{
long l { 0L };
// print "generic A constructor"
A<long, std::vector<int>> alv(l, true);
// print "S constructor>" and "S specific A constructor"
A<long, S<int>> als(l, true);
}
Related Topics
Does Constraint Subsumption Only Apply to Concepts
C++ Get All Bytes of a File in to a Char Array
When Will Gnu C++ Support C++11 Without Explicitly Asking for It
Use Createprocess to Run a Batch File
Reason Why Not to Have a Delete MACro for C++
Why Is It Not Possible to Overload Class Templates
Error with Address of Parenthesized Member Function
Inadvertent Use of = Instead of ==
How to Directly Bind a Member Function to an Std::Function in Visual Studio 11
C++ - Repeatedly Using Istringstream
Get the Status of a Std::Future
Need to Call a Function at Periodic Time Intervals in C++
How to Make an Array with a Dynamic Size? General Usage of Dynamic Arrays (Maybe Pointers Too)
How to Make 'New[]' Default-Initialize the Array of Primitive Types