I want to create a generic class containing a method displaying one message if the type of the class is int and the other when it's double. Here's my code:
template<class T>
class A {
public:
template <T> void B();
};
template<class T>
void A<int>::B{
//some code here
}
template<class T>
void A<double>::B{
//some code here
}
I got the following errors:
'double': illegal type for non-type template parameter '__formal'
'A<int>::B': unable to match function definition to an existing declaration
Thanks in advance for any solutions.
A couple of things:
There's no reason for B to be a template. You want to specialize for A
B is a method. Methods accept parameters. When defining the method, you omitted the parenthesis ()
Template specialization always involves an empty template parameter <>
Code:
template<class T>
class A {
public:
void B();
};
template<>
void A<int>::B(){
std::cout << "A<int>::B" << std::endl;
}
template<>
void A<double>::B(){
std::cout << "A<double>::B" << std::endl;
}
Demo
If you feel compelled to make B a template, I should note that in general one does not perform template specialization on functions. This is primarily because they cannot be partially specialized, and it's almost always better to write an overload. In your case, B takes no arguments, so there's some argument to be made in favor of specialization.
More often than not, one would use a tag dispatching approach instead, coupled with a helper function so that they can choose their desired function by taking advantage of overloading instead. Here's a simple example of tag dispatching for your case:
template<class T>
class A {
public:
template<class U>
void B()
{
B(ATag<U>{});
}
private:
template<class U>
struct ATag{};
void B(ATag<int>)
{
std::cout << "B<int>" << std::endl;
}
void B(ATag<double>)
{
std::cout << "B<double>" << std::endl;
}
};
tag dispatch demo
Related
I have some class like
enum Type {ONE, TWO};
template <enum Type T>
class A {
void foo() {}
};
I want to specify the function foo() according to the template argument T of the class. Is it possible to be done inside the class ? Or, how to do it outside the class?
Edit:
what if my class is
template <class U, enum Type T>
class A {
void foo() {}
};
This class cannot be simply specialized by giving two version of foo
I found a solution at What is wrong with partial template specialization?
which may turn out to make the code very long.
Is there any other solution to this, or should some other design be used ?
You can explicitly specialize members functions of class templates. You simply do:
template <>
void A<ONE>::foo()
{
//ONE stuff
}
Alternatively, you can use tag-dispatching. In this particular instance, they don't make much sense, but they might if your requirements are slightly different.
template <enum Type T>
class A
{
public:
void foo() {fooImpl(std::conditional_t<T==ONE, std::true_type, std::false_type>());}
void fooImpl(std::true_type)
{
cout << "ONE" << endl;
}
void fooImpl(std::false_type)
{
cout << "TWO" << endl;
}
};
With the above definition,
int main()
{
A<ONE>().foo();
A<TWO>().foo();
return 0;
}
prints
ONE
TWO
I'd like to call a function AsJson in a unified way irrespective of whether I'm dealing with an instance or a primitive type, or anything else.
I thought I could define an abstract base class which classes could inherit, and then define a template function that calls the AsJson member function when the template is specialized to appropriate classes. For other types, they could just specialize the template function.
Something like this:
#include <iostream>
class IInstrumented {
public:
virtual void AsJson() const = 0;
};
template <typename T>
void AsJson(const T&);
template <typename T>
void AsJson(const IInstrumented& instrumented) {
instrumented.AsJson();
}
class Foo : public IInstrumented {
public:
void AsJson() const override { std::cout << "A Foo!" << std::endl; }
};
template <>
void AsJson(const int& x) {
std::cout << "An integer!" << std::endl;
}
int main() {
Foo foo;
AsJson(foo);
int x = 3;
AsJson(x);
}
Unfortunately, this results in the following linker error:
special.cpp:(.text+0x56): undefined reference to `void AsJson<Foo>(Foo const&)'
Is this approach workable as is? Is the fix something relatively minor, or is an entirely different approach warranted?
Although there is an accepted answer, I thought I would point out why you had the error in the first place.
When compiling
AsJson(foo);
the compiler is looking for this template instantiation:
template <>
void AsJson(const Foo&);
which is not defined(undefined reference error) because
template <typename T>
void AsJson(const T&);
has no implementation. It is not using this template specialization:
template <>
void AsJson(const IInstrumented& instrumented) {
instrumented.AsJson();
}
because it is not the best candidate while deducting type. By changing the code to:
AsJson<IInstrumented>(foo);
You then explicitly tell the compiler which template specialization you want to use. Previous answer assume all types will inherits from IInstrumented which might not be the case hence why the static_assert checking for type was added.
By providing a default implementation, you can avoid the necessity to inherits from IInstrumentable. Adding an assert in there might help catching serializing unknown types.
You should change
template <typename T>
void AsJson(const IInstrumented& instrumented) {
instrumented.AsJson();
}
to
template <typename T>
void AsJson(const T& instrumented) {
instrumented.AsJson();
}
And then:
$ ./bla
A Foo!
An integer!
Now if you want to ensure that T is derived from IInstrumented. You should add (c++11 only) :
template <typename T>
void AsJson(const T& instrumented) {
static_assert(std::is_base_of<IInstrumented, T>::value,
"T must be a descendant of IInstrumented"
);
instrumented.AsJson();
}
Then with
class Bar {
public:
void AsJson() { std::cout << "A Foo!" << std::endl; }
};
The following code:
Bar bar;
AsJson(bar);
raises:
bla.cpp: In instantiation of ‘void AsJson(const T&) [with T = Bar]’:
bla.cpp:38:13: required from here
bla.cpp:13:3: error: static assertion failed: T must be a descendant of IInstrumented
static_assert(std::is_base_of<IInstrumented, T>::value,
See also How to ensure that the template parameter is a subtype of a desired type?
I would like to have a Queue template class which can specify the internal container structure via the template argument and specialize the Top function (as different container use different function name for accessing the front item), like the following code:
template<class I, class C = std::queue<I>>
class Queue
{
C items;
public:
I* Top()
{
std::cout << "this is a queue" << std::endl;
return &items.front();
}
};
template<class I>
void I* Queue<I, std::priority_queue<I>>::Top()
{
std::cout << "this is a priority_queue" << std::endl;
return &items.top();
}
However, this piece of codes cause a lot compilation errors. Does anyone could give me a hint that am I going into a wrong direction of designing the template class? Thanks.
You're trying to partially specialise a (member) function template. Function templates cannot be partially specialised in C++. You'd have to partially specialise the entire class, or find other ways of doing what you want. For example, you could use a trait in Top():
I* Top()
{
return MyQueueTraits<I, C>::GetTop(items);
}
template <class I, class C>
struct MyQueueTraits
{
static I* GetTop(C &c) { return &c.front(); }
};
template <class I>
struct MyQueueTraits<I, std::priority_queue<I>>
{
static I* GetTop(std::pirority_queue<I> &c) { return &c.top(); }
};
Please refer to the below code
Specialized function in non specialized Template class
Is it possible to write a specialized function foo, for non specialized template class MyClass [Line Number 7] ? If yes, then, what is the syntax for the same.
Regards,
Atul
This can be done if you create a full specialization of the class template. Just refer to the answer in this question: If I want to specialise just one method in a template, how do I do it?
Otherwise if you want to have a given function with the same signature have two different behaviors depending on the instantiated version of the class, and that instantiation is a partial specialization of the template class, you will have to make a separate specialization of the template class.
Keep in mind that if you want to avoid redundant code in this second case, you can always create a base template class that will have the functionality that will not change, and then create derived template classes that will contain the unique functionality necessary for each partial specialization.
Look at my example below, I have tried answer your question (if I guessed right) in the simplest code possible by me:
#include <iostream>
using namespace std;
template<typename T>
class Some
{
public:
template<typename U> void foo(U val);
};
template<typename T>
template<typename U>
void Some<T>::foo(U val)
{
cout << "Non specialized" << endl;
}
template<>
template<>
void Some<char>::foo(char val)
{
cout << "Char specialized" << endl;
}
int main()
{
Some<int> t1;
t1.foo(5);
Some<char> t2;
t2.foo('c');
return 0;
}
The important thing to note here is that "You cannot specialize your class and function Independently" i.e you have to specialize both at the same time as done in the example.
Also, with this you lose the opportunity to specialize your class for that data type "char" in this case. (Need to confirm on this).
UPDATE :: Confirmed on point 2.
If you wanted to specialize MyClass< bool >::Foo, it would look like this:
template <>
void MyClass<bool>::Foo(bool A)
{
// code goes here
}
If you are asking that,
(1) you want a function Foo() which doesn't take any argument and
returns void inside MyClass
(2) This Foo() should be exclusive to the MyClass when the
template type is bool, i.e. only for MyClass<bool>
then here is the way:
template<class Precision>
class MyClass {
...
public:
...
void Foo (); // don't implement here
};
...
template<>
void MyClass<bool>::Foo () // implementing only for 'MyClass<bool>'
{ // invoking for other 'MyClass<>' will result in compiler error
...
}
I have a visitor class resembling this:
struct Visitor
{
template <typename T>
void operator()(T t)
{
...
}
void operator()(bool b)
{
...
}
};
Clearly, operator()(bool b) is intended to be a specialization of the preceding template function.
However, it doesn't have the template<> syntax that I'm used to seeing before it, declaring this as a template specialization. But it does compile.
Is this safe? Is this correct?
Your code is not a template specialization, but rather a non-templated function. There are some differences there. The non-templated operator() will take precedence over a templated version (for an exact match, but type conversions will not take place there) but you can still force the templated function to be called:
class Visitor
{
public: // corrected as pointed by stefanB, thanks
template <typename T>
void operator()( T data ) {
std::cout << "generic template" << std::endl;
}
void operator()( bool data ) {
std::cout << "regular member function" << std::endl;
}
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB
void Visitor::operator()( int data ) {
std::cout << "specialization" << std::endl;
}
int main()
{
Visitor v;
v( 5 ); // specialization
v( true ); // regular member function
v.operator()<bool>( true ); // generic template even if there is a non-templated overload
// operator() must be specified there (signature of the method) for the compiler to
// detect what part is a template. You cannot use <> right after a variable name
}
In your code there is not much of a difference, but if your code needs to pass the template parameter type it will get funnier:
template <typename T>
T g() {
return T();
}
template <>
int g() {
return 0;
}
int g() {
return 1;
}
int main()
{
g<double>(); // return 0.0
g<int>(); // return 0
g(); // return 1 -- non-templated functions take precedence over templated ones
}
What you have here is function overloading; to obtain template specialization, you indeed need the template <> syntax. However, you should be aware that these two approaches, even if they may seem identical, are subtly different, and even the compiler might get lost when choosing the right function to call. Listing all the possible cases would be a little too long for this answer, but you might want to check Herb Sutter GoTW #49 on the subject.
Oh, it'll compile. It just won't be a template function. You'll have a regular non-template function instead of a template specialization.
It's safe, and actually likely what you want as well. The Visitor pattern is normally implemented by overloading. Specializing function templates isn't really a good idea anyway.
What you did is not template serialization, but function overloading. It is safe.
P.S. It's difficult to say whether it's correct or not, without knowing what you're trying to achieve. Keep in mind that no matter is it template or overloaded function, your operator will be chosen in compile time. If you need to run-time dispatch, you need polymorphism, not overloading. Well, you probably know it anyway; just in case.
You have
void operator()(bool b) that is non
templated function
template< typename T > void
operator()(T t) which is a separate
base template that overloads the
above
You could have a full specialization of the second one as in template<> void operator(int i) which would only be considered when void operator()(bool b) did not match.
The specialization of base template is used to select which of the base template methods to call. However in your case you have a non-templated method that will get considered first.
The article Why Not Specialize Function Templates? gives quite good explanation of how the method is selected.
In sumary:
Non template functions are
considered first (this is your plain
operator()(bool) above)
Function base templates get checked
second (this is your templated
function), the most specialized base-template is selected and then if it has specialization for the exact types that specialization is used otherwise the base template is used with 'the correct' types (see explanation in the article)
Example:
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
cout << "template <> void operator()<>(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
You get calls to:
operator()(bool b) <-- first non template method that matches
template <> void operator()(int i) <-- the most specialized specialization of templated function is called