Is the following specialization of the member function template bar valid? It compiles on gcc 4.5.3 and VS .NET 2008. I'm confused because I vaguely recall reading that function templates cannot be specialized.
struct Foo
{
template<typename T>
void bar();
};
template<typename T>
void Foo::bar(){}
template<>
void Foo::bar<bool>(){}
int main()
{
Foo f;
f.bar<char>();
f.bar<bool>();
}
Function template can not be partially specialized, but can be explicitly specialized, your code is perfectly correct.
Function template partial specialization was considered in C++11 but was rejected since function template overloading can be used to solve the same issue. However, there're some caveats which have to be looked for when doing this.
Example:
template <typename T> void foo(T);
void foo(int);
foo(10); // calls void bar(int)
foo(10.f); // calls void bar(T) [with T = float]
foo(10u); // calls void bar(T) [with T = unsigned int]!!
For your case, something of this sort might work
struct Foo
{
template<typename T>
void bar(T dummy);
void bar(bool dummy);
};
template<typename T>
void Foo::bar(T dummy) { }
void Foo::bar(bool dummy) { }
int main()
{
Foo f;
f.bar('a');
f.bar(true);
}
Related
At which moment the function templates within the following class template are instantiated?
// a.h
#pragma once
template <typename T>
class A {
public:
template <typename T2> void func1(T2 t);
void func2(T t);
T func3();
void func4();
// SECONDARY ISSUE
// Is there any difference in writing this:
A& operator=(A const&) = default;
// or this:
A<T>& operator=(A<T> const&) = default;
};
-----------------------------
// a.cpp
#include "a.h"
template <typename T>
template <typename T2>
void A<T>::func1(T2 t)
{
// do sth
}
template <typename T>
void A<T>::func2(T t)
{
// do sth
}
template <typename T>
T A<T>::func3()
{
T t;
// do sth
return t;
}
template <typename T>
void A<T>::func4()
{
T t;
// do sth with t
}
template class A<int>; // explicit instantiation
-----------------------------
// main.cpp
#include "a.h"
int main()
{
A<int> a1;
a1.func1<double>(1.);
a1.func1(1.);
a1.func2(2);
a1.func3();
a1.func4();
}
In a free function template the template is instantiated when it's called with a concrete type or with explicit instantiation.
What's the case with class templates? I guess func2() - func4() are instantiated with the explicit class template instantiation template class A<int>;. Or takes the instantiation place at the moment of the first function call, i.e. for example a1.func2(2.)?
In case of func1() the instantiation takes probably place with the call of a1.func1<double>(1.); as this is the first time when the second template parameter T2 is known?
Concerning the secondary issue:
Does it matter if I write A or A<T>? I think it's the same but I am not sure about it.
Methods of class templates are only instantiated when called. For illustration consider:
#include <type_traits>
template <typename T>
struct foo {
void only_for_int() {
static_assert(std::is_same<T,int>::value);
}
};
int main(){
foo<int> f;
f.only_for_int(); // OK (T == int)
foo<double> d; // OK
//d.only_for_int(); // ERROR: static assert failed
}
Creating a foo<double> is fine. You just cannot call its method only_for_int.
The fact that not every method must be valid is quite handy to allow types that cannot support all the templates requirements to use at least a subset of the templates methods.
The following code:
template <typename S, typename T>
struct foo {
void bar();
};
template <typename T>
void foo <int, T>::bar() {
}
gives me the error
invalid use of incomplete type 'struct foo<int, T>'
declaration of 'struct foo<int, T>'
(I'm using gcc.) Is my syntax for partial specialization wrong? Note that if I remove the second argument:
template <typename S>
struct foo {
void bar();
};
template <>
void foo <int>::bar() {
}
then it compiles correctly.
You can't partially specialize a function. If you wish to do so on a member function, you must partially specialize the entire template (yes, it's irritating). On a large templated class, to partially specialize a function, you would need a workaround. Perhaps a templated member struct (e.g. template <typename U = T> struct Nested) would work. Or else you can try deriving from another template that partially specializes (works if you use the this->member notation, otherwise you will encounter compiler errors).
Although coppro mentioned two solutions already and Anonymous explained the second one, it took me quite some time to understand the first one. Maybe the following code is helpful for someone stumbling across this site, which still ranks high in google, like me. The example (passing a vector/array/single element of numericalT as dataT and then accessing it via [] or directly) is of course somewhat contrived, but should illustrate how you actually can come very close to partially specializing a member function by wrapping it in a partially specialized class.
/* The following circumvents the impossible partial specialization of
a member function
actualClass<dataT,numericalT,1>::access
as well as the non-nonsensical full specialisation of the possibly
very big actualClass. */
//helper:
template <typename dataT, typename numericalT, unsigned int dataDim>
class specialised{
public:
numericalT& access(dataT& x, const unsigned int index){return x[index];}
};
//partial specialisation:
template <typename dataT, typename numericalT>
class specialised<dataT,numericalT,1>{
public:
numericalT& access(dataT& x, const unsigned int index){return x;}
};
//your actual class:
template <typename dataT, typename numericalT, unsigned int dataDim>
class actualClass{
private:
dataT x;
specialised<dataT,numericalT,dataDim> accessor;
public:
//... for(int i=0;i<dataDim;++i) ...accessor.access(x,i) ...
};
If you need to partially specialise a constructor, you might try something like:
template <class T, int N>
struct thingBase
{
//Data members and other stuff.
};
template <class T, int N> struct thing : thingBase<T, N> {};
template <class T> struct thing<T, 42> : thingBase<T, 42>
{
thing(T * param1, wchar_t * param2)
{
//Special construction if N equals 42.
}
};
Note: this was anonymised from something I'm working on. You can also use this when you have a template class with lots and lots of members and you just want to add a function.
If you're reading this question then you might like to be reminded that although you can't partially specialise methods you can add a non-templated overload, which will be called in preference to the templated function. i.e.
struct A
{
template<typename T>
bool foo(T arg) { return true; }
bool foo(int arg) { return false; }
void bar()
{
bool test = foo(7); // Returns false
}
};
In C++ 17, I use "if constexpr" to avoid specialize (and rewrite) my method. For example :
template <size_t TSize>
struct A
{
void recursiveMethod();
};
template <size_t TSize>
void A<TSize>::recursiveMethod()
{
if constexpr (TSize == 1)
{
//[...] imple without subA
}
else
{
A<TSize - 1> subA;
//[...] imple
}
}
That avoid to specialize A<1>::recursiveMethod().
You can also use this method for type like this example :
template <typename T>
struct A
{
void foo();
};
template <typename T>
void A<T>::foo()
{
if constexpr (std::is_arithmetic_v<T>)
{
std::cout << "arithmetic" << std::endl;
}
else
{
std::cout << "other" << std::endl;
}
}
int main()
{
A<char*> a;
a.foo();
A<int> b;
b.foo();
}
output :
other
arithmetic
The following code:
template <typename S, typename T>
struct foo {
void bar();
};
template <typename T>
void foo <int, T>::bar() {
}
gives me the error
invalid use of incomplete type 'struct foo<int, T>'
declaration of 'struct foo<int, T>'
(I'm using gcc.) Is my syntax for partial specialization wrong? Note that if I remove the second argument:
template <typename S>
struct foo {
void bar();
};
template <>
void foo <int>::bar() {
}
then it compiles correctly.
You can't partially specialize a function. If you wish to do so on a member function, you must partially specialize the entire template (yes, it's irritating). On a large templated class, to partially specialize a function, you would need a workaround. Perhaps a templated member struct (e.g. template <typename U = T> struct Nested) would work. Or else you can try deriving from another template that partially specializes (works if you use the this->member notation, otherwise you will encounter compiler errors).
Although coppro mentioned two solutions already and Anonymous explained the second one, it took me quite some time to understand the first one. Maybe the following code is helpful for someone stumbling across this site, which still ranks high in google, like me. The example (passing a vector/array/single element of numericalT as dataT and then accessing it via [] or directly) is of course somewhat contrived, but should illustrate how you actually can come very close to partially specializing a member function by wrapping it in a partially specialized class.
/* The following circumvents the impossible partial specialization of
a member function
actualClass<dataT,numericalT,1>::access
as well as the non-nonsensical full specialisation of the possibly
very big actualClass. */
//helper:
template <typename dataT, typename numericalT, unsigned int dataDim>
class specialised{
public:
numericalT& access(dataT& x, const unsigned int index){return x[index];}
};
//partial specialisation:
template <typename dataT, typename numericalT>
class specialised<dataT,numericalT,1>{
public:
numericalT& access(dataT& x, const unsigned int index){return x;}
};
//your actual class:
template <typename dataT, typename numericalT, unsigned int dataDim>
class actualClass{
private:
dataT x;
specialised<dataT,numericalT,dataDim> accessor;
public:
//... for(int i=0;i<dataDim;++i) ...accessor.access(x,i) ...
};
If you need to partially specialise a constructor, you might try something like:
template <class T, int N>
struct thingBase
{
//Data members and other stuff.
};
template <class T, int N> struct thing : thingBase<T, N> {};
template <class T> struct thing<T, 42> : thingBase<T, 42>
{
thing(T * param1, wchar_t * param2)
{
//Special construction if N equals 42.
}
};
Note: this was anonymised from something I'm working on. You can also use this when you have a template class with lots and lots of members and you just want to add a function.
If you're reading this question then you might like to be reminded that although you can't partially specialise methods you can add a non-templated overload, which will be called in preference to the templated function. i.e.
struct A
{
template<typename T>
bool foo(T arg) { return true; }
bool foo(int arg) { return false; }
void bar()
{
bool test = foo(7); // Returns false
}
};
In C++ 17, I use "if constexpr" to avoid specialize (and rewrite) my method. For example :
template <size_t TSize>
struct A
{
void recursiveMethod();
};
template <size_t TSize>
void A<TSize>::recursiveMethod()
{
if constexpr (TSize == 1)
{
//[...] imple without subA
}
else
{
A<TSize - 1> subA;
//[...] imple
}
}
That avoid to specialize A<1>::recursiveMethod().
You can also use this method for type like this example :
template <typename T>
struct A
{
void foo();
};
template <typename T>
void A<T>::foo()
{
if constexpr (std::is_arithmetic_v<T>)
{
std::cout << "arithmetic" << std::endl;
}
else
{
std::cout << "other" << std::endl;
}
}
int main()
{
A<char*> a;
a.foo();
A<int> b;
b.foo();
}
output :
other
arithmetic
I can't explain myself why partial template specialization is not possible in the case below. Is there any technical reason? And mostly, is there any work around to make it work?
template <int a, int b>
void foo();
// DO NOT COMPILE
template <int a>
void foo<a, 999>() {
}
// COMPILE
template <>
void foo<999, 999>() {
}
template <int a, int b>
void foo() {
}
You may use struct for partial specialization:
template <int a, int b> struct foo_helper { void operator()() { /*code*/ } };
template <int a> struct foo_helper<a, 999> { void operator()() { /*code*/ } };
template <> struct foo_helper<999, 999> { void operator()() { /*code*/ } };
template <int a, int b>
void foo()
{
foo_helper<a, b>{}();
}
Functions can not be partially specialized. Usually it is much easier to overload a function or use SFINAE.
If it is not possible - like in this case, since SFINAE and overloads can only work on types - one can partially specialize a class having said function as it's static member - though it is usually more typing.
The following code:
template <typename S, typename T>
struct foo {
void bar();
};
template <typename T>
void foo <int, T>::bar() {
}
gives me the error
invalid use of incomplete type 'struct foo<int, T>'
declaration of 'struct foo<int, T>'
(I'm using gcc.) Is my syntax for partial specialization wrong? Note that if I remove the second argument:
template <typename S>
struct foo {
void bar();
};
template <>
void foo <int>::bar() {
}
then it compiles correctly.
You can't partially specialize a function. If you wish to do so on a member function, you must partially specialize the entire template (yes, it's irritating). On a large templated class, to partially specialize a function, you would need a workaround. Perhaps a templated member struct (e.g. template <typename U = T> struct Nested) would work. Or else you can try deriving from another template that partially specializes (works if you use the this->member notation, otherwise you will encounter compiler errors).
Although coppro mentioned two solutions already and Anonymous explained the second one, it took me quite some time to understand the first one. Maybe the following code is helpful for someone stumbling across this site, which still ranks high in google, like me. The example (passing a vector/array/single element of numericalT as dataT and then accessing it via [] or directly) is of course somewhat contrived, but should illustrate how you actually can come very close to partially specializing a member function by wrapping it in a partially specialized class.
/* The following circumvents the impossible partial specialization of
a member function
actualClass<dataT,numericalT,1>::access
as well as the non-nonsensical full specialisation of the possibly
very big actualClass. */
//helper:
template <typename dataT, typename numericalT, unsigned int dataDim>
class specialised{
public:
numericalT& access(dataT& x, const unsigned int index){return x[index];}
};
//partial specialisation:
template <typename dataT, typename numericalT>
class specialised<dataT,numericalT,1>{
public:
numericalT& access(dataT& x, const unsigned int index){return x;}
};
//your actual class:
template <typename dataT, typename numericalT, unsigned int dataDim>
class actualClass{
private:
dataT x;
specialised<dataT,numericalT,dataDim> accessor;
public:
//... for(int i=0;i<dataDim;++i) ...accessor.access(x,i) ...
};
If you need to partially specialise a constructor, you might try something like:
template <class T, int N>
struct thingBase
{
//Data members and other stuff.
};
template <class T, int N> struct thing : thingBase<T, N> {};
template <class T> struct thing<T, 42> : thingBase<T, 42>
{
thing(T * param1, wchar_t * param2)
{
//Special construction if N equals 42.
}
};
Note: this was anonymised from something I'm working on. You can also use this when you have a template class with lots and lots of members and you just want to add a function.
If you're reading this question then you might like to be reminded that although you can't partially specialise methods you can add a non-templated overload, which will be called in preference to the templated function. i.e.
struct A
{
template<typename T>
bool foo(T arg) { return true; }
bool foo(int arg) { return false; }
void bar()
{
bool test = foo(7); // Returns false
}
};
In C++ 17, I use "if constexpr" to avoid specialize (and rewrite) my method. For example :
template <size_t TSize>
struct A
{
void recursiveMethod();
};
template <size_t TSize>
void A<TSize>::recursiveMethod()
{
if constexpr (TSize == 1)
{
//[...] imple without subA
}
else
{
A<TSize - 1> subA;
//[...] imple
}
}
That avoid to specialize A<1>::recursiveMethod().
You can also use this method for type like this example :
template <typename T>
struct A
{
void foo();
};
template <typename T>
void A<T>::foo()
{
if constexpr (std::is_arithmetic_v<T>)
{
std::cout << "arithmetic" << std::endl;
}
else
{
std::cout << "other" << std::endl;
}
}
int main()
{
A<char*> a;
a.foo();
A<int> b;
b.foo();
}
output :
other
arithmetic