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
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
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.
Is it possible to specialize a few functions for a template class without specializing the whole thing?
For example:
template <typename T>
struct A {
int foo();
};
template <typename T>
int A<T>::foo() { return 1;}
template <>
struct A<int> {
int bar() { return 2; };
};
main() {
A<int> a;
a.foo(); //1
a.bar(); //2
A<double> b;
b.foo(); //1
b.bar(); // ERROR
}
Or something similar?
No. But there is a way around it.
Hand off the logic to a free function template specialisation from within the template class method.
template<class T>
int delegated_foo() {
return 1;
}
// now specialise
template<>
int delegated_foo<int>() {
return 2;
}
template <typename T>
struct A {
int foo() {
return delegated_foo<T>();
}
};
To answer the comment - if you want to partially specialise a class, you can delegate common logic in to a template base class.
template<class T>
struct a_common {
void common_function() {
// define here. Compiler will generate 1 for each T
}
};
template<class T>
struct A : public a_common<T>
{
int something_i_might_specialise();
};
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
}