I'm code reviewing a colleagues code and found this:
Header file:
template<class T>
class MyClass
{
void Execute();
}
Cpp file:
void MyClass<int>::Execute()
{
// something
}
void MyClass<string>::Execute()
{
// something else
}
The code is specializing the function, but without using template specialization syntax. I guess it's working ok, but is it valid?
Yes, it's perfectly valid to specialize methods of a template class.
But your syntax is wrong, it should be: (sorry, didn't see you were missing the template<>
initially. Just assumed it was there and thought you were asking about member function specialization.)
template<>
void MyClass<int>::Execute()
{
// something
}
template<>
void MyClass<string>::Execute()
{
// something else
}
You need only declare these in the header. If you implement them in the header as well, you'll need to mark them inline
to prevent multiple definition.
When calling a method, the version that suits the call most is called. Otherwise, the default.
In your case, if you specialize the template with a class X
and attempt to call Execute
, you'll get a linker error because you haven't provided a default implementation, nor a specialization for Execute
for X
.
The question has already been answered, but let me draw attention to subtle differences between three cases.
header:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
template <> void Foo<int>::f();
source:
template <> void Foo<int>::f() { /* ... */ }
In this case, Foo<T>::f()
can be called for any T
. The definition for the general case is auto-generated from the template; the definition for Foo<int>::f()
is the one provided. Having the specialization in the header alerts every consuming translation unit that a separate symbol is to be looked up, rather than to use the template.
header:
template <typename T> struct Foo
{
void f();
};
source:
template <> void Foo<int>::f() { /* ... */ }
In this case, only Foo<int>::f()
can be used; everything else will cause a linker error. Since there is no definition of the function in the template, every use of the template will cause a new symbol to be emitted, and only the one for Foo<int>::f()
is provided by the shown translation unit.
header:
template <typename T> struct Foo
{
void f() { /* stuff */ }
};
source:
template <> void Foo<int>::f() { /* ... */ }
This is a violation of the one-definition rule, since there are now multiple definitions of Foo<int>::f()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With