Given the following two structs, one could derive from both nested 'Nested' classes, and call foo() and bar() from the derived object:
struct WithNested1 {
template<class T> struct Nested {
void foo();
};
};
struct WithNested2 {
template<class T> struct Nested {
void bar();
};
};
struct Test : WithNested1::Nested<Test>,
WithNested2::Nested<Test>
{
};
Test test;
test.foo();
test.bar();
But, if both of the outer classes were passed as variadic template arguments, how would you derive from them?
For example, this fails to compile:
template<typename... Ts>
struct Test : Ts::template Nested<Test>...
{
};
Test<WithNested1, WithNested2> test;
test.foo();
test.bar();
error: 'foo' : is not a member of 'Test'
error: 'bar' : is not a member of 'Test'
strangely, it compiles if the calls to foo() and bar() are removed.
template <typename... Ts>
struct Test : Ts::template Nested<Test<Ts...>>...
{
};
This is the same answer as above but I figured I'd explain how it works. First in your example Test has no template param (which the compiler should warn you of), but which should we give it. The point of CRTP is to give the class you inherit from a template param that is the same as your type, that way it has access to your methods and members through the of the template param. Your type in this case is Test<Ts...> so that is what you have to pass it. As #aschepler already pointed out normally you could use Test by itself but it's not in scope until your already inside the class.
I think this is a cleaner way of doing what you want.
template <typename T>
struct A {
void bar (){
static_cast<T*>(this)->val = 3;
}
};
template <typename T>
struct B {
void foo (){
static_cast<T*>(this)->val = 90;
}
};
template <template<class> class ... Ts>
struct Test : Ts<Test<Ts...>>...
{
int val;
};
int main() {
Test<A,B> test;
test.foo();
test.bar();
return 0;
}
The "injected class name" Test which can be used as an abbreviation of Test<Ts...> is not in scope where you tried to use Nested<Test>, since the class scope does not begin until the { token.
Use
template<typename... Ts>
struct Test : public Ts::template Nested<Test<Ts...>>...
{
};
This works:
template<typename... Ts>
struct Test : Ts::template Nested<Test<Ts...>>...
// ^^^^^^^
{
};
9/2:
[...]. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name. [...]
14.6.1/1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injectedclass-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-typespecifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.
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.
I want to use 'MyType' from the base class in the 'DoesBlah' test below.
#include <gtest/gtest.h>
template <typename T>
struct MemberVariable
{
T m_t;
};
struct Base : public ::testing::Test
{
template <typename MemberType>
using MyType = MemberVariable<MemberType>;
};
template <typename DerivedType>
struct Derived : public Base
{
};
typedef ::testing::Types<int, char> MyTypes;
TYPED_TEST_CASE(Derived, MyTypes);
TYPED_TEST(Derived, DoesBlah)
{
MyType<TypeParam> test;
test.m_t = (TypeParam)1;
ASSERT_EQ(test.m_t, 1);
}
However, I get the following compilation error:
gti/specific/level/Test.t.cpp: In member function 'virtual void Derived_DoesBlah_Test<gtest_TypeParam_>::TestBody()':
gti/specific/level/Test.t.cpp:25:5: error: 'MyType' was not declared in this scope
MyType<TypeParam> test;
I tried using TestFixture::MyType, typename TestFixture::MyType, but both did not work.
How can I get Derived to recognize that there's something called 'MyType'?
With some simplifications, the macro TYPED_TEST(Derived, DoesBlah) expands to something like:
template <typename TypeParam>
class Derived_DoesBlah_Test : public Derived<TypeParam>
{
private:
typedef Derived<TypeParam> TestFixture;
virtual void TestBody();
};
template <typename TypeParam>
void Derived_DoesBlah_Test<TypeParam>::TestBody()
So the {} block that follows is the function definition for a member of a template class which derives from Derived<TypeParam>. The typedef for TestFixture is available, but it depends on the template parameter TypeParam, so it is considered a dependent type. What's more, you want to access a template member of that dependent type. So you need both the typename and template keywords:
{
typename TestFixture::template MyType<TypeParam> test;
test.m_t = (TypeParam)1;
ASSERT_EQ(test.m_t, 1);
}
For more about dependent types and using the typename and template keywords in declarations and expressions, see this SO question.
I have this code:
template <typename A>
class templatedclass {
public:
using type = templatedclass;
};
template <typename A>
class sinkstuff {
public:
void print() {
cout << "generic sinkstuff";
}
};
template <typename A>
class sinkstuff <templatedclass<A>> {
public:
void print() {
cout << "partiallyspecialized sinkstuff";
}
};
template <typename NtoA>
struct pass_parameter : sinkstuff<typename templatedclass<NtoA>::type> {};
int main() {
pass_parameter<int> obj;
obj.print();
cout << is_same<templatedclass<int>, typename templatedclass<int>::type>::value; // 1, yes
}
I always thought the "using directive" was a typedef on steroids. How come I can use "templatedclass<int>::type" without specifying the parameter again, i.e. "templatedclass<int>::type<int>" ?
Isn't "using type = templatedclass" just a textual substitution? Am I missing something?
The name of a class is "injected" into the class, this is called the injected-class-name. It is similar to:
class my_class_name
{
public:
typedef ::my_class_name my_class_name;
};
(But this of course doesn't compile, a class may not have a manually declared member of the same name as the class.)
Class templates also have an injected-class-name, and it can be used to refer to the class template itself, or the current specialization (including the current template arguments), depending on the context:
[temp.local]/1
Like normal (non-template) classes, class templates have an injected-class-name. The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent
to the template-name followed by the template-parameters of the class template enclosed in <>.
This doesn't have anything to do with the using directive. Within the definition of A<T> (and the using directive is in that scope), saying A is the same as saying A<T>.
It's the same reason you may write:
template <typename T>
struct A
{
void foo(const A&);
};
instead of
template <typename T>
struct A
{
void foo(const A<T>&);
};
For more information, search for "injected-class-name".
If I want to use a member of a template base class from a template derived class, I have to bring it into scope as such:
template <typename T>
struct base
{
void foo();
};
template <typename T>
struct derived : base<T>
{
using base<T>::foo;
};
Why can't I place this using statement into a local scope, like other using statements?
template <typename T>
struct base
{
void foo();
};
template <typename T>
struct derived : base<T>
{
void f()
{
using base<T>::foo; // ERROR: base<T> is not a namespace
}
};
The purpose of using base<T>::foo in the function scope is that you want to call foo in the function, and since it gives error, you cannot do that.
If you want to call the functon (otherwise why you would do that), then you can do these which are allowed:
this->template base<T>::foo(); //syntax 1
this->base<T>::foo(); //syntax 2 - simple
this->foo(); //syntax 3 - simpler
However, you cannot write this:
foo() ; //error - since foo is in base class template!
//if you write `using base<T>::foo` at class scope, it will work!
Demo at ideone : http://www.ideone.com/vfDNs
Read this to know when you must use template keyword in a function call:
Ugly compiler errors with template
The standard (draft 3225) says in [namespace.udecl]:
A using-declaration for a class member shall be a member-declaration. [ Example:
struct X {
int i;
static int s;
};
void f() {
using X::i; // error: X::i is a class member
// and this is not a member declaration.
using X::s; // error: X::s is a class member
// and this is not a member declaration.
}
— end example ]
A using-directive has no such restriction, however ([namespace.udir]):
when looking up a namespace-name in a using-directive, only namespace names are considered
It appears to me that C++ does not allow member template specialization in any scope other than namespace and global scope (MS VSC++ Error C3412). But to me it makes sense to specialize a base class's primary member template in the derived class because that is what derived classes do - specialize things in the base class. For instance, consider the following example:
struct Base
{
template <class T>
struct Kind
{
typedef T type;
};
};
struct Derived : public Base
{
/* Not Allowed */
using Base::Kind;
template <>
struct Kind <float>
{
typedef double type;
};
};
int main(void)
{
Base::Kind<float>::type f; // float type desired
Derived::Kind<float>::type i; // double type desired but does not work.
}
My question is why isn't it allowed?
I get what you're trying to do, but you are not doing it right. Try this :
struct Base{};
struct Derived{};
// Original definition of Kind
// Will yield an error if Kind is not used properly
template<typename WhatToDo, typename T>
struct Kind
{
};
// definition of Kind for Base selector
template<typename T>
struct Kind<Base, T>
{
typedef T type;
};
// Here is the inheritance you wanted
template<typename T>
struct Kind<Derived, T> : Kind<Base, T>
{
};
// ... and the specialization for float
template<>
struct Kind<Derived, float>
{
typedef double type;
};
My question is why isn't it allowed?
From my copy of the draft it appears that the following puts the above restriction:
In
an explicit specialization declaration for a class template, a member of a class template or a class member
template, the name of the class that is explicitly specialized shall be a simple-template-id.
The workaround is to specialize the enclosing class.
I will "ignore" the standard specifications and try a logical argument:
If you have two classes:
class A
{
struct S { };
};
class B: public A
{
struct S { };
};
A::S and B::S are two different types. Extending the logic to the template specializations, when you try to specialize an inner class declared in base class through an inner class in derived class, you actually are trying to define a different type, with the same name (but another naming scope).