When does a template end?
Let's have a look at this code:
template <class T>
class thatClass
{
T a, b;
thatClass (T x, T y) {a = x; b = y;}
};
template <class T>T aFunc(T one, T two)
{
return one+two;
}
So when does template <class T> end? Does it always end after at the end of a class or function definition or what? And why can't you just use the one template you declared for both classes and functions, so in this case, I could use the template parameter T for both the function aFunc and for the class definition?
The scope of the template parameter ends with the scope of the templated subject:
template <class T>
class thatClass
{
T a, b;
thatClass (T x, T y) {a = x; b = y;}
}; // << ends here
template <class T>T aFunc(T one, T two)
{
return one+two;
} // << ends here
And why can't you just use the one template you declared for both classes and functions, so in this case, I could use the template parameter T for both the function aFunc and for the class definition?
You can't because template parameter scope is always bound to a class/struct or function definition. That's defined as such in the language.
One could think of templating a whole namespace, but that's not an available language feature, and I'm not sure if that would be a good idea at all.
As you seem to be confused I'll add some variations:
template <class T>
class thatClass
{
T a, b;
thatClass (T x, T y) {a = x; b = y;}
// A member funcion that uses the same template parameter and accesses
// the class member variables
T aFunc() { return a+b; }
// A static member funcion that uses the same template parameter and
// calculates the result from the parameters
static T aStaticFunc(T one, T two) { return one+two; }
};
Related
Note: this seems to be a repost of a problem: C++ - Overload templated class method with a partial specilization of that method
I have boiled down a problem I am having with C++ template specialization down to a simple case.
It consists of a simple 2-parameter template class Thing, where I would like to specialize Thing<A,B>::doSomething() for B=int.
#include <cstdio>
// A 3-parameter template class.
template <class A, class B>
class Thing
{
public:
Thing(A a, B b) : a_(a), b_(b) {}
B doSomething();
private:
A a_;
B b_;
};
// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
return b_;
}
// This specialization does not work!
template <class A>
int Thing<A,int>::doSomething()
{
return b_+1;
}
int main() {
// Setup our thing.
Thing<double,int> thing(1.0,2);
// This doesn't compile - but works with the generic case.
printf("Expecting 3, and getting %i\n", thing.doSomething());
// Clean up.
return 0;
}
Unfortunately, g++ exits with the error:
partial_specialization.cpp:30: error: invalid use of incomplete type ‘class Thing<A, int>’
partial_specialization.cpp:8: error: declaration of ‘class Thing<A, int>’
The clang++ compiler is a bit more verbose, but has the same problem:
partial_specialization.cpp:30:19: error: nested name specifier 'Thing<A, int>::' for declaration does not
refer into a class, class template or class template partial specialization
int Thing<A,int>::doSomething()
~~~~~~~~~~~~~~^
partial_specialization.cpp:32:12: error: use of undeclared identifier 'b_'
return b_+1;
^
2 errors generated.
I have read and understood that partial template specializations on functions aren't allowed - but I thought I was partially specializing over classes of Thing in this case.
Any ideas?
What I did: A workaround, as determined from the link provided by the accepted answer:
template< class T >
inline T foo( T const & v ) { return v; }
template<>
inline int foo( int const & v ) { return v+1; }
// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
return foo(b_);
}
Partial specialization of a function template, whether it is member function template or stand-alone function template, is not allowed by the Standard:
template<typename T, typename U> void f() {} //okay - primary template
template<typename T> void f<T,int>() {} //error - partial specialization
template<> void f<unsigned char,int>() {} //okay - full specialization
But you can partially specialize the class template itself. You can do something like this:
template <class A>
class Thing<A,int> //partial specialization of the class template
{
//..
int doSomething();
};
template <class A>
int Thing<A,int>::doSomething() { /* do whatever you want to do here */ }
Note that when you partially specialize a class template, then the template parameter-list of member function (in its definition outside the class), must match the template parameter list of the class template partial specialization. That means, for the above partial specialization of the class template, you cannot define this:
template <class A>
int Thing<A,double>::doSomething(); //error
Its not allowed, because the template parameter-list in function definition didn't match the template parameter-list of the class template partial specialization. §14.5.4.3/1 from the Standard (2003) says,
The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.[...]
For more on this, read my answer here:
C++ - Overload templated class method with a partial specilization of that method
So what is the solution? Would you partially specialize your class along with all the repetitive work?
A simple solution would be work delegation, instead of partially specializing the class template. Write a stand-alone function template and specialize this as:
template <class B>
B doTheActualSomething(B & b) { return b; }
template <>
int doTheActualSomething<int>(int & b) { return b + 1; }
And then call this function template from doSomething() member function as:
template <class A, class B>
B Thing<A,B>::doSomething() { return doTheActualSomething<B>(b_); }
Since in your particular case, doTheActualSomething needs to know the value of only one member, namely b_, the above solution is fine, as you can pass the value to the function as argument whose type is the template type argument B, and specialization for int is possible being it full-specialization.
But imagine if it needs to access multiple members, type of each depends on the template type argument-list, then defining a stand-alone function template wouldn't solve the problem, because now there will be more than one type argument to the function template, and you cannot partially specialize the function for just, say, one type (as its not allowed).
So in this case you can define a class template instead, which defines a static non-template member function doTheActualSomething. Here is how:
template<typename A, typename B>
struct Worker
{
B doTheActualSomething(Thing<A,B> *thing)
{
return thing->b_;
}
};
//partial specialization of the class template itself, for B = int
template<typename A>
struct Worker<A,int>
{
int doTheActualSomething(Thing<A,int> *thing)
{
return thing->b_ + 1;
}
};
Notice that you can use thing pointer to access any member of the class. Of course, if it needs to access private members, then you've to make struct Worker a friend of Thing class template, as:
//forward class template declaration
template<typename T, typename U> struct Worker
template <class A, class B>
class Thing
{
template<typename T, typename U> friend struct Worker; //make it friend
//...
};
Now delegate the work to the friend as:
template <class A, class B>
B Thing<A,B>::doSomething()
{
return Worker<A,B>::doTheActualSomething(this); //delegate work
}
Two points to be noted here:
In this solution, doTheActualSomething is not a member function template. Its not enclosing class which is template. Hence we can partially specialize the class template anytime, to get the desired effect of the partial member function template specialization.
Since we pass this pointer as argument to the function, we can access any member of the class Thing<A,B>, even private members, as Worker<T,U> is also a friend.
Complete online demo : http://www.ideone.com/uEQ4S
Now there is still a chance of improvement. Now all instantiations of Worker class template are friends of all instantiation of Thing class template. So we can restrict this many-to-many friendship as:
template <class A, class B>
class Thing
{
friend struct Worker<A,B>; //make it friend
//...
};
Now only one instantiation of Worker class template is a friend of one instantiation of Thing class template. That is one-to-one friendship. That is, Worker<A,B> is a friend of Thing<A,B>. Worker<A,B> is NOT a friend of Thing<A,C>.
This change requires us to write the code in somewhat different order. See the complete demo, with all the ordering of class and function definitions and all:
http://www.ideone.com/6a1Ih
This is a very often found problem, and there is a surprisingly simple solution. I will show it in an artificial example, because it's more clearer than to use your code, and you will have to understand it to adapt it to your code
template<typename A, typename B>
struct TwoTypes { };
template<typename A, typename B>
struct X {
/* forwards ... */
void f() { fImpl(TwoTypes<A, B>()); }
/* special overload for <A, int> */
template<typename A1>
void fImpl(TwoTypes<A1, int>) {
/* ... */
}
/* generic */
template<typename A1, typename B1>
void fImpl(TwoTypes<A1, B1>) {
/* ... */
}
};
Explicitly specializing functions is never (almost never?) the right way. In my work as a programmer, I've never explicitly specialized a function template. Overloading and partial ordering is superior.
With a class defined as follows:
template <typename T>
class A {
private:
T a;
public:
A(T& a) : a_(a) { }
template <typename D>
void Eval(D& arg)
{
// ...
}
};
template A<int>;
I want to explicitly instantiate one instance of the class, and I want this class to have one explicit instantiation of Eval. The intention here is to get a member function pointer that avoids ambiguity:
auto eval_ptr = &A<int>::Eval;
The ambiguity is not coming from anything to do with template instantiation of the class, it's caused by Eval also being a templated function.
&A<int>::Eval does not point to a function, it points to a template. And there is just no such type as a "pointer to a template".
If you want a pointer to A<int>::Eval, you need to specify D as well.
auto eval_ptr = &A<int>::Eval<int>; works just fine for example.
Addendum: Pointers-to-templates do exist in the grammatical sense, but there is no type an object can have to hold one of them. They must be immediately casted/decayed to a specific overload in order to be used, which doesn't come into play here since you want to store it in an auto.
For example: The following is fine because there's clearly only one "version" of Eval that can be meant:
void bar(void (A<int>::*arg)(int&)) {}
void foo() {
bar(&A<int>::Eval);
}
The very simple solution was specifying both template parameters:
template <typename T>
class A
{
private:
T a;
public:
A(T &a) : a_(a) {}
template <typename D>
void Eval(D &arg)
{
arg+=1;
}
};
int main()
{
auto p = &A<int>::Eval<int>;
}
Lets say I have this class:
template <class T>
class Test
{
Test(T* x);
const T* const t;
int i{0};
};
I want t to always be initialized with x:
template <class T> Test<T>::Test(T* x) : t{x} {}
And I have two specializations:
template <> Test<Foo>::Test(Foo* x) : t{x} { i = 1; }
template <> Test<Bar>::Test(Bar* x) : t{x} { i = 2; }
Next, I'm extending the class with some other stuff, and that first (templated) constructor does a lot more than just setting t.
All things that I want to do for both T = Foo and T = Bar.
Is there some way that I can call the templated constructor from the specialized constructors?
//This does not work, since it will create a delegation cycle
template <> Test<Foo>::Test(Foo* x) : Test(x) { i = 1; }
template <> Test<Bar>::Test(Bar* x) : Test(x) { i = 2; }
You can use a delegating constructor for this.
You can create a private constructor, that takes the pointer for t, and an int for i. Then you can use that to set x and i, and run all of the shared code.
That would look like:
template <class T>
class Test
{
public:
Test(T* x) : Test(x, 0) { /*code for default case, runs after delegate*/ }
private:
Test(T* t, int i) : t(t), i(i) { /*code to run for everything*/ }
const T* const t;
int i;
};
template <> Test<Foo>::Test(Foo* x) : Test(x, 1) { /*code only for Foo, runs after delegate*/ }
template <> Test<Foo>::Test(Bar* x) : Test(x, 2) { /*code only for Bar, runs after delegate*/ }
Can the delegate constructor be the generic/templated constructor (with the same signature as the specific, specialized constructors for Foo and Bar)?
No, that isn't possible. When you specialize a function template, you aren't creating a new function, but instead specifying that if T gets deduced to the type you specify in the specialization, then use the specialization definition in place of the generic one.
That is why I have "all three constructors" (the generic and the two specializations) call Test(T* t, int i), which handles the code that is shared by all cases.
have you thought about inheritance? The first thing that comes to my mind is making a Test class derived from the base class that will have all the things that you wanted the same for both foo and bar took care of. So you could call the base class constructor inside derived class (Test), and then just do things for Foo and bar.
This has been driving me crazy for the past couple hours, and I cannot seem to get around this problem. I have distilled the problem down to these 60 lines of code (including a main function).
#include <iostream>
namespace n1 {
// the general definition
template <class X, class Y> void f(X&, const Y&)
{
std::cout << "general template definition.\n";
}
} // namespace n1
namespace n2 {
// CRTP
template <class Derived> class A
{
int data;
// partial function template specialization for n1::f, and declare
// it a friend too, so that it may access the data attribute of A
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
}; // class A
} // namespace n2
namespace n1 {
// implementation for this particular function template specialization
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
{
std::cout << "partial template specialization: " << a.data << "\n";
}
} // namespace n1
namespace n2 {
// Another class!
class B : public A<B>
{
}; // class B
} // namespace n2
namespace n1 {
// --------------------
// tricky part is here!
// --------------------
template <class Y> void f(n2::B& b, const Y& y)
{
// FAIL! not a friend! How?
f(static_cast<n2::A<n2::B>&>(b), y);
}
} // namespace n1
int main()
{
n2::B b;
int x;
n1::f(b, x); // should print "partial template specialization"
return 0;
}
So, what I "want" is to have the compiler select my function template specialization of n1::f whenever it is invoked with a concrete subclass of A<Derived>. In order to make sure that the compiler favors my specialization, I need to supply, for every subclass (B in this case), also a template specialization for n1::f that simply delegates the call. When that happens, I expect the data member variable of A<Derived> to be accessible to n1::f, because I declare n1::f to be a friend of A<Derived>. However, GCC complains that A<Derived>::data is private and inaccessible, see this snippet on Coliru.
Is this construction possible? If so, how can I get around the compiler complaining that A<Derived>::data is not accessible? (Making it public is not an option).
Your class definition must look like this:
template <class Derived> class A
{
int data;
template <class D, class Y> friend void n1::f(A<D>& a, const Y& y);
};
In fact, function declaration is:
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
While your friend declaration is:
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
In this case, they are different beasts and that's why you receive that error. As you can see, template parameters lists are different. That's not a declaration of a function with a separated definition. They are two different function templates, one declared and the other one both declared and defined.
In other terms, in your code you are declaring a friend function but you never define it. On the other side, you introduced a free function template that cannot read the data member for it's private and the function isn't a friend one of A<Derived>.
See it running on wandbox.
I have three classes:
//Template class for function 1
template<class P> class wrap4{
P p;
public:
wrap4(P&& p1) : p(std::forward<P>(p1)) {}
double f(double x){
return p.FN(x);
}
};
//Simple concrete parameter
struct Parameter{
double FN(double x){
return x;
}
};
//Method used in the program
template<class Function> class B {
Function F;
public:
B(Function && f) : F(std::forward<Function>(f)) {}
double use(double x){
return F.f(x);
}
};
template<class Function> B<Function> make_B(Function && F){ return B<Function>{std::forward<Function>(F)}; }
template<class P> B<P> make_wrap4(P && F){ return B<P>{std::forward<P>(F)}; }
Basically, I want to plug wrap4 into B, but to do so I have to instantiate it with Parameter. I've tried the following:
auto A = make_B(make_wrap4{Parameter p});
but this doesn't work, I get the compiler error
error: conversion from 'B<B<Parameter> >' to non-scalar type 'B<wrap4<Parameter> >' requested
Of course, this is a silly example because I know I can just implement B with Parameter, but of course I'm trying to do something more complicated in the long run where I really need a B to take a template class which doesn't admit a default constructor as an argument.
Do I need to implement a template template parameter here?
You have a copy&paste error you should be able to spot from the error message:
template<class P> B<P> make_wrap4(P && F){ return B<P>{std::forward<P>(F)}; }
should be
template<class P> wrap4<P> make_wrap4(P && F){ return wrap4<P>{std::forward<P>(F)}; }
// ^^ here ^^ and here
and then you should call make_wrap4 like a function, i.e. not with an initializer list.
A little sidenote: you don't have three classes, you have one class and two class templates. It's also not a template class, as the comment states for wrap4.
wrap4 is a class template.
wrap4<int> and wrap4<Parameter> are classes, which you get by instantiating the class template. Some people would call such classes template class as well.