I've recently discovered template specialization in C++.
template <typename T>
void fct(void) {}
template <>
void fct<int>(void) {}
int main(void) {
fct<int>();
return 0;
}
I'd like to use template specialization for member functions inside a class.
class MyClass {
public:
template <typename T>
static void fct(void) {}
template <>
static void fct<int>(void) {}
};
int main(void) {
MyClass::fct<int>();
return 0;
}
Unfortunately, compiling with g++ gives me the following error:
error: explicit specialization in non-namespace scope ‘struct MyClass’
error: template-id ‘toto<int>’ in declaration of primary template
I've noticed that doing template specialization works in main scope or in a namespace but not in a struct or in a class.
I've found something on stackoverflow about using a namespace like in the following code:
namespace myNameSpace {
template <typename T>
void fct(void) {}
template <>
void fct<int>(void) {}
}
class MyClass {
public:
template <typename T>
static void fct(void) {
myNameSpace::fct<T>();
}
};
int main(void) {
MyClass::fct<int>();
return 0;
}
What am I doing wrong? Is it possible to make template specialization with member functions? If not, what is the best way to get around this? Is there a better way than using namespace to get around this?
Write the specialization after the class definition:
class MyClass
{
public:
template <typename T>
static void fct(void) {}
};
template <>
void MyClass::fct<int>() {}
Related
I have two classes class A and class B both of them are template classes for a member function in A I want it to act in a special way when the type of A is B
and in a normal way for any other types I don't know how to do this ?
template <class B>
class B
{
private:
T m;
public:
...... any member functions
}
template <class T>
class A
{
private:
T var;
public:
void doSomething();
};
template <class T>
void A<T>::doSomething(){...........//implementation}
template <class T>
void A<B<T>>::doSomething(){................//different implementation}
You can specialize A this way:
template <class T>
class A<B<T>> {
// ...
};
This is an instance of partial template specialization.
If you refuse to specialize the entire class, you can defer the work from A<T>::doSomething() to a function doSomethingForA<T>(A &) that would be partially specialized, and that would possibly be friend of A<T>.
Hope this solves your problem:
#include <iostream>
template <typename T>
struct B {};
template <typename T> struct A;
template <typename T>
void doSomething(T&) { std::cout << "General\n"; }
template <typename T>
void doSomething(A<B<T>>&) { std::cout << "Special\n"; }
template <typename T>
struct A {
void doSomething() {
::doSomething(*this);
}
};
int main()
{
A<int> general;
A<B<int>> special;
general.doSomething();
special.doSomething();
}
Trying to nail down the logic behind explicit specialization of members of class templates I composed this code below:
#include <iostream>
using namespace std;
template<class T> class X
{
public:
template<class U> class Y
{
public:
template<class V> void f(U,V);
void g(U);
};
};
template<> template<> template<class V>
void X<int>::Y<int>::f(int, V) {}
int main() {
X<int>::Y<int> b;
b.f(1, 1);
}
It compiles without any problems. But when i introduce changes shown below, it refuses to compile at all:
#include <iostream>
using namespace std;
template<class T> class X
{
public:
template<class U> class Y
{
public:
template<class V> void f(U,V);
void g(U);
};
};
template<> template<class U> template<class V> // changes
void X<int>::Y<U>::f(U, V) {} // changes
int main() {
X<int>::Y<int> b;
b.f(1, 1);
}
Error:
1>d:\projects\programs\youtube\lesson\lesson\main.cpp(17): error C3860: template argument list following class template name must list parameters in the order used in template parameter list
1>d:\projects\programs\youtube\lesson\lesson\main.cpp(17): error C3855: 'X': template parameter 'T' is incompatible with the declaration
Can somebody explain to me what is going on here? Thank you!
I'm trying to partially specialize a templated member function of an untemplated class:
#include <iostream>
template<class T>
class Foo {};
struct Bar {
template<class T>
int fct(T);
};
template<class FloatT>
int Bar::fct(Foo<FloatT>) {}
int main() {
Bar bar;
Foo<float> arg;
std::cout << bar.fct(arg);
}
I'm getting the following error:
c.cc:14: error: prototype for ‘int Bar::fct(Foo<FloatT>)’ does not match any in class ‘Bar’
c.cc:9: error: candidate is: template<class T> int Bar::fct(T)
How can I fix the compiler error?
Partial specialization of functions (member or otherwise) is not allowed.
Use overload:
struct Bar {
template<class T>
int fct(T data);
template<class T> //this is overload, not [partial] specialization
int fct(Foo<T> data);
};
In C++, I am trying to specialize a templated function for a object that is templated itself.
Here is a basic example:
test.h:
template <class T>
class myC {
T x;
};
template <class U>
void f(U y) {
}
template <>
template <class T>
void f<myC<T> >(myC<T> y) {
}
test.cpp
#include "test.h"
int main() {
myC<double> m;
f(m);
}
GCC 4.6.1 gives me the following error message:
In file included from test.cpp:1:0:
test.h:13:25: error: too many template parameter lists in declaration of ‘void f(myC<T>)’
test.h:13:6: error: template-id ‘f<myC<T> >’ for ‘void f(myC<T>)’ does not match any template declaration
test.h:13:25: note: saw 2 ‘template<>’, need 1 for specializing a member function template
Is this at all possible? Or is there another way to accomplish the same goal?
template <>
template <class T>
void f<myC<T> >(myC<T> y) {
}
What you're atttempting to be doing here is called partial specialization which is not allowed in case of function template.
A function template is either fully specialized, or not specialized at all. No partial specialization of function template is allowed by the language specification.
So you can overload the function template as:
template <class T>
void f(myC<T> y) //note that it is overload, not specialization
{
}
which is allowed, and preferred over even fully specialization of template.
Read these articles by Herb Sutter:
Why Not Specialize Function Templates?
Template Specialization and Overloading
You cannot specialize a template function; only template classes can be specialized. Edit: Nawaz's answer is correct: it's partial specialization that is not allowed for template functions, only for classes. A full specialization is possible:
template <class U> void f(U y) {}
template<> void f<double>(double y) {} // specialization for double
Note that the template argument need not be explicitly specified if it can be deduced from the context:
template<> void f<>(int y) {} // specialization for int
In your case, full specialization is not possible because the function argument is a template class. However, a template function, like any function, can be overloaded. In your case, it will be like this:
template <class T>
class myC {
T x;
};
template <class U>
void f(U y) {
}
template <class T>
void f(myC<T> y) {
}
int main() {
myC<double> m;
f(m);
return 0;
}
As far as I can tell, you cannot specialize template functions, only template classes (or structs).
But that is hardly a limitation: just declare a struct with static public member functions and mave the template parameters to the struct:
template <class T>
class myC {
T x;
};
template <class U>
struct Foo
{
static void f(U y) {
}
};
template <>
template <class T>
struct Foo<myC<T> >
{
static void f(myC<T> y) {
}
};
The drawback is that class templates do not solve the template parameters automatically. But that can be easlily solved with a function template, similar to the original one:
template <class U>
void f(U y) {
return Foo<U>::f(y);
}
template <class T>
class Test
{
public:
template<class T>
void f(); //If i define function here itself, error is not reported.
};
template <class T>
void Test<T>::f()
{
} //Error here.
int main()
{
Test<float> ob;
ob.f<int>();
}
It produces below error.
error C2244: 'Test<T>::f' : unable to match function definition to an
existing declaration
definition 'void Test::f(void)'
existing declarations 'void Test::f(void)'
Error says declaration and definitions have the same prototype but not matching.
Why is this an error ? and how to solve it ?
If i define function within the class, it doesn't report error.
But i want to define outside the class.
Change as
template <class T>
class Test
{
public:
template<class U>
void f();
};
template <class T>
template<class U>
void Test<T>::f()
{
}
....
public:
template<class T> // this shadows the previous declaration of typename T
void f();
};
Change the parameter name. Here is the working code.