Given a template class with a single parameter, I can define an implementation for a specific specialization:
template<int N>
struct Foo {
Foo( );
};
Foo<2>::Foo( ) { //works (on MS Visual 2012, even though it's not the most correct form)
}
For a multiple parameter template, is it possible to define an implementation for a partial specialization?
template <class X, int N>
struct Bar {
Bar( );
};
template <class X>
Bar<X,2>::Bar( ) { //error
}
For partial specializations, you need to first define the specialization of the class template itself before you can go defining its members:
template <class X, int N>
struct Bar {
Bar();
};
template<class X>
struct Bar<X,2> {
Bar();
};
template <class X>
Bar<X,2>::Bar( ) { }
The correct form for the first one that you said it works is:
template<int N>
struct Foo {
Foo( );
};
template<>
Foo<2>::Foo( ) { //works
}
You need to specialize the class itself before specializing its members. So
template <class X, int N>
struct Bar {
Bar();
};
template<class X>
struct Bar<X,2> {
Bar();
};
template<class X>
Bar<X,2>::Bar( )
{ //error gone
}
And you may further specialize your constructor as:
template<>
Bar<int,2>::Bar( )
{ //error gone
}
Related
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
By using template template parameters one can pass to a class a templated class without specifying types on its parameters. I was wondering is there a way to pass into a template template parameter a templated signature of a function to be able to specialize which variant of the function is to be considered forward.
To be clear - I know I cannot do that:
template <class T>
void foo() { /*...*/ }
template <template <class...> class FooType>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo)> f;
}
But somehow I would like to be able to pass templated signature of function to Foo. Is it even possible?
I couldn't believe that this is not possible so I searched a bit and found a way to do exactly what I wanted. I used templated using with a syntax:
template <template<class... Args> class FooType>
struct Foo {
FooType<int> ft;
};
template <class Res, class... Args>
using FooSignature = Res(*)(Args...);
int foo() {
return 1;
}
int main() {
Foo<FooSignature> f;
f.ft = foo;
}
This however still leaves the question how can this be possible since the standard states something opposite.
In the example below one has a template template parameter that accepts the preferred signature for the function.
Because of the specialization and the lack of a body for the template class, only types for callables are accepted.
It is a generalization of what the OP actually asked:
#include<cassert>
template<typename F>
struct S;
template<typename R, typename... Args>
struct S<R(Args...)> {
using type = R(*)(Args...);
};
template<template<typename> class F>
struct T {
typename F<void(int)>::type ft;
typename F<double(double, double)>::type gt;
};
void f(int) { }
double g(double x, double y) { return x+y; }
int main() {
T<S> t;
t.ft = f;
t.gt = g;
t.ft(42);
auto v = t.gt(1., 1.);
assert(v == 2.);
}
As can be seen in this answer
Template of function pointer is illegal in C++
The C++ Standard says in $14/1,
A template defines a family of classes or functions.
Further quoting from the linked answer:
Please note that it does NOT say "A template defines a family of classes, functions or function pointers"
However, you can pass concrete function pointers, and specialise on their signature:
#include <iostream>
template <class T>
void foo(T) { }
template <typename>
struct Foo;
template<typename T>
struct Foo<void(T)>
{
void cb() { std::cout << "T\n"; }
};
template<>
struct Foo<void(int)>
{
void cb() { std::cout << "int\n"; }
};
template<>
struct Foo<void(double)>
{
void cb() { std::cout << "double\n"; }
};
int main()
{
Foo<decltype(foo<int >)>().cb(); // outputs 'int'
Foo<decltype(foo<double>)>().cb(); // outputs 'double'
Foo<decltype(foo<char >)>().cb(); // outputs 'T'
return 0;
}
template of template is still a template.
template <class T>
void foo() { /*...*/ }
template <typename T>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo<int>)> f;
}
You cannot pass a function template as an argument. What you can do is wrap a function template in a generate lambda taking a tag parameter:
template <class T> struct tag_t { using type = T; };
template <class T>
void foo() { ... }
template <class F>
void call_func_with(F f) {
f(tag_t<int>{} );
f(tag_t<double>{} );
}
call_with_func([](auto tag) { foo<decltype(tag)::type>(); } );
Here, f(tag_t<X>{} ) ends up calling foo<X>(), as desired.
How to take care of the repetitions below for the Object::func() definitions without using macros?
template <int N> struct Object {};
template <> struct Object<0> {
// special stuff
void func();
};
template <> struct Object<1> {
// special stuff
void func();
};
template <> struct Object<2> {
// special stuff
void func();
};
template <int N> struct Thing {};
void Object<0>::func() {
Thing<0> a;
// do stuff with a
}
void Object<1>::func() {
Thing<1> a;
// do exact same stuff with a
}
void Object<2>::func() {
Thing<2> a;
// do exact same stuff with a
}
Private inheritance, with the base having template int N? Meta-template stuff? CRTP? I can't figure it out. Note that
// special stuff
means that the template specializations are necessary--I'm just not showing how they are specialized. I'm only showing the one function func() that are almost identical to all of them.
Using inheritance you can avoid specialization for the common code. How about:
template <int N> struct ObjectBase {
void func();
};
template <int N> struct Thing {};
template <int N>
void ObjectBase<N>::func() {
Thing<N> a;
// do stuff with a
}
template <> struct Object<0>: private ObjectBase<0> {
// special stuff
};
template <> struct Object<1>: private ObjectBase<1> {
// special stuff
};
template <> struct Object<2>: private ObjectBase<2> {
// special stuff
};
For your question, my solution is to use template template parameters to define your template class, I feel this is the way to avoid re-define common things over and over.
Below is the code that I just coded and tested in Visual Studio 2013:
#include <iostream>
template <int N> struct Thing { int x; Thing() : x(N) {}; };
template <int N, template<int N> class T> struct Object { void func(); };
template <int N, template<int N> class T> void Object<N, T>::func()
{
T<N> a;
std::cout << a.x << std::endl;
};
int main()
{
Object<0, Thing> obj0;
Object<11, Thing> obj11;
Object<22, Thing> obj22;
obj0.func();
obj11.func();
obj22.func();
return 0;
}
This code will print:
0
11
22
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