I have a template class in which I am specializing a couple of methods. For some reason, when I added a specialization for a struct, it seems to be conflicting with the specialization for bool. I am getting a type conversion error because it is trying to set the struct = bool (resolving to the wrong specialization). Here is some code
.h:
typedef struct foo {
...
}
template <class T> class bar {
template <class T> void method1() {...}
template <> void method1<bool>() {...}
template <> void method1<foo>() {...}
}
.cpp
template class bar<bool>;
template class bar<foo>;
I am getting the error inside method1<bool> because it is setting T=foo instead of resolving it to method1<foo>.
Any ideas?
The first part of your code is already incorrect. C++ does not support explicit specialization of "nested" (member) templates without explicit specialization of the enclosing template.
In the context of your code, it is illegal to explicitly specialize template method method1 without explicitly specializing the entire class template bar.
If your member template function member1 depended on some parameters, you could use overloading instead of template specialization as a workaround. But since it doesn't, you have to redesign you templates somehow. What you do above is, once again, illegal in C++.
The errors you get further down can easily be (and most probably are) induced by that original problem.
P.S. The description of the problem you posted implies that your code compiles. What you posted should not compile for the reasons described above. This suggests that you are posting fake code. Post real code.
(EDITED)
You may try the following, which delegates the method implementation to a templated helper class.
.h:
typedef struct Foo {
...
}
template<class T_Bar, class T2> struct BarMethod1;
template <class T> class Bar
{
template<class T2> void method1(...)
{
BarMethod1<Bar, T2>(...)(...);
}
}
template <class T_Bar, class T2> class BarMethod1
{void operator()(...){...}};
template <class T_Bar> class BarMethod1<T_Bar, bool>
{void operator()(...){...}};
template <class T_Bar> BarMethod1<T_Bar, Foo>
{void operator()(...){...}};
.cpp
template class Bar<bool>;
template class BarMethod1<Bar<bool>, bool>;
template class BarMethod1<Bar<bool>, Foo>;
template class Bar<Foo>;
template class BarMethod1<Bar<Foo>, bool>;
template class BarMethod1<Bar<Foo>, Foo>;
Related
I am considering Class1, Class2, Class3.
Class2 and Class3 have a partial specialisation with int, so they are identical in their definition.
On the other hand, Class1 has a specialisation for Class3<T> and for a general template template with only one argument, i.e. Unary<T>. So Class1 has no specialisation for Class2<T>.
It happens that Class1 <Class3<T>>::type is actually Class3<T>. Indeed I explicitly wrote the specialisation. However, the compiler says Class1 <Class2<T>>::type it is not defined. But I defined the specialisation for a the template template case, Class1<Unary<T>>. Why is the compiler not recognising it? How can I make the compiler choose the most specialised case (Class1 <Class3<T>>::type), if it exists, and, if does not, the template template case (Class1<Unary<T>>)? Thank you
template<typename...T>
class Class1;
template<typename...T>
class Class2;
template<typename...T>
class Class3;
template<>
class Class2<int>
{};
template<>
class Class3<int>
{};
template<typename T>
class Class1<Class3<T>>
{
public:
using type=Class3<T>;
};
template<template<class> class Unary, typename T>
class Class1<Unary<T>>
{
public:
using type=Unary<T>;
};
Before C++17 such template:
template<template<class> class Unary, typename T>
class Class1<Unary<T>>
should not mach with variadic templates. Same for templates with defaulted arguments (check this with std::vector for example) - Template template parameter and default values. It was a defect in standard and fix came in C++17
I have JsonFormatter template class that is specialized for different types like arithmetic etc... in the following way:
template <class T, typename Enable = void>
class JsonFormatter;
template <class T>
class JsonFormatter<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
{
};
it is not clear how to specialize it for a concrete type like std::string, for example? My first idea was something like this:
template <>
class JsonFormatter<std::string, std::true_type>
{
};
but this does not compile. When I use
JsonFormatter<std::string>
I get
"undefined class 'JsonFormatter<std::string,void>'"
The important point is that the specialization has to match the primary. In this case, the primary is set up such that the 2nd template parameter is going to be void - it's not intended to be provided by the user, it's just there to enable people to use enable_if.
std::true_type doesn't match void, which is why it doesn't work. When the user writes JsonFormatter<std::string>, the default argument will get instantiated as void - so they're looking for the specialization JsonFormatter<std::string, void>... which isn't what you provided.
You want:
template <>
class JsonFormatter<std::string, void>
{ };
Or even just:
template <>
class JsonFormatter<std::string>
{ };
Since the default argument will get filled in just fine.
This is how you specialize the template:
template <>
class JsonFormatter<std::string, void>
{
};
You can also use std::enable_if, but I don't recommend it since it a simple specialization is much easier. std::enable_if works correctly with SFINAE only. So it needs to depend on a template parameter:
template <class T>
class JsonFormatter<T, std::enable_if_t<std::is_same_v<T, std::string>>>
{
};
it is not clear how to specialize it for a concrete type like std::string, for example?
Have you tried simply with
template <>
class JsonFormatter<std::string>
{
};
?
Should works.
The second template parameter become void according the dafault value defined in the main version.
I try to do the following, I think the example should be self-explaining:
template <class CLASS, class PARAM>
void call(){
CLASS<PARAM>::do_something();
}
On the angular brackets between CLASS and PARAM on line 3, the compiler says:
error: expected unqualified-id
Can I fix this problem or is it not allowed what I try to do?
template <
template <typename T> class CLASS,
typename PARAM>
void call()
{
CLASS<PARAM>::do_something();
}
The template parameter CLASS is declared to be a class, or also a typename, I.e. the name of a type.
template<typename X> struct A;
Here A isn't a type, it's a template. To obtain a type, you need to "apply"(*) the template: A<int>.
If you write CLASS<PARAM>, you're trying to apply a type to a type. This won't work. It's like trying to call a value 42(parameter), only on the type level.
So you need to specify that CLASS is something which can be applied, that it's a template:
template <typename T> class CLASS
So, for reference, the complete solution is:
template <template <typename T> class CLASS, class PARAM>
void call(){
CLASS<PARAM>::do_something();
}
(*) A template is a function on type level: It takes one or more types, and returns a new type.
In addition to the answers given by #DanielJour and #Nasser, I want to mention that the name T of the type name for the template template parameter CLASS can be omitted, because it is not used. So, the condensed solution would look like this:
template <template <typename> class CLASS, typename PARAM>
void call()
{
CLASS<PARAM>::do_something();
}
Reference: Template Template Parameters.
template <typename T>
void foo(T t)
{
... // do stuff with type T
}
template <typename T>
class class_template
{
// class body
};
template<> // failed attempt at full specialization
void foo(class_template<T> t) // which doesn't work of course
{
//full specialization for all classes of class_template
}
In the above code how do I explicitly specialize function foo with a class template?
In the above code how do I explicitly specialize function foo with a class template?
You cannot. This is the whole point of partial specialisations. But they don’t work for functions.
You have two solutions:
Overload the function. This usually works.
Refer the work to a class template, which can be partially specialised. That is, inside your function, call a (static) function in a class template, and specialise that.
There are a few questions already similar to this already on stack overflow, but nothing that seemd to directly answer the question I have. I do apologise if I am reposting.
I'd like to overload a few methods of a templated class (with 2 template parameters) with a partial template specialisation of those methods. I haven't been able to figure out the correct syntax, and am starting to think that it's not possible. I thought I'd post here to see if I can get confirmation.
Example code to follow:
template <typename T, typename U>
class Test
{
public:
void Set( T t, U u );
T m_T;
U m_U;
};
// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
m_T=t;
m_U=u;
}
// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
m_T=t;
m_U=u+0.5f;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test<int, int> testOne;
int a = 1;
testOne.Set( a, a );
Test<int, float> testTwo;
float f = 1.f;
testTwo.Set( a, f );
}
I know that I could write a partial specialisation of the entire class, but that kinda sucks. Is something like this possible?
(I'm using VS2008)
Edit: Here is the compile error
error C2244: 'Test::Set' : unable to match function definition to an existing declaration
Thanks :)
You cannot partially specialize a member function without defining partial specialization of the class template itself. Note that partial specialization of a template is STILL a template, hence when the compiler sees Test<T, float>, it expects a partial specialization of the class template.
--
$14.5.4.3/1 from the C++ Standard (2003) says,
The template parameter list of a
member of a class template partial
specialization shall match the
template parameter list of the class
template partial specialization. The
template argument list of a member of
a class template partial
specialization shall match the
template argument list of the class
template partial specialization. A
class template specialization is a
distinct template. The members of the
class template partial specialization
are unrelated to the members of the
primary template. Class template
partial specialization members that
are used in a way that requires a
definition shall be defined; the
definitions of members of the primary
template are never used as definitions
for members of a class template
partial specialization. An explicit
specialization of a member of a class
template partial specialization is
declared in the same way as an
explicit specialization of the primary
template.
Then the Standard itself gives this example,
// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }
// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
I hope the quotation from the Standard along with the example answers your question well.
The particular problem you're sketching is easy:
template< class T >
inline T foo( T const& v ) { return v; }
template<>
float foo( float const& v ) { return v+0.5; }
Then call foo from your Test::Set implementation.
If you want the full generality, then similarly use a helper class with static helper member functions, and partially specialize that helper class.
Cheers & hth.,
There's also another solution to the partial specialization problem, if you don't want to introduce additional functions, methods or classes to your code.
#include <type_traits>
template <typename T1, typename T2>
class C
{
void f(T1 t1);
}
template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
if (std::is_same<T2, float>::value)
// Do sth
else
// Do sth
}