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".
Related
template <class T> class Stack {
public:
Stack();
};
template <class T> class Stack {
public:
Stack<T>();
}
By the way, what's the meaning of <T>?
From injected-class name in class template's documentation:
Otherwise, it is treated as a type-name, and is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.
This means that both the given snippets in your example are equivalent(Source). In the 1st snippet, the declaration Stack(); for the default ctor is actually the same as writing:
Stack<T>(); //this is the same as writing `Stack();`
what's the meaning of ?
Stack<T> denotes an instantiated class-type for some given T. For example, when T=int then Stack<int> is a separate instantiated class-type. Similarly, when say T=double then Stack<double> is another distinct instantiated class-type.
When instantiating a template(class or function) we generally(not always as sometimes it can be deduced) have to provide additional information like type information for template type parameters etc. And the way to provide this additional information is by giving/putting it in between the angle brackets.
For example,
template <class T> class Stack {
public:
Stack(); //this is the same as Stack<T>(); due to injected class name in class template
};
template<typename T>
Stack<T>::Stack()
{
}
int main()
{
Stack<int> obj; //here we've provided the additional information "int" in between the angle brackets
}
The above code will generate a class type Stack<int> that will look something like:
template<>
class Stack<int>
{
public:
Stack<int>()
{
}
};
I have trouble to build a class which itself contains a subclass which self derives from class which needs template parameters from the top class. Sound horrible and it is indeed deep inside some MTP construction. But have a look on a simple example which I could shrink from the real code.
I leave the names as is in my original source. They are not important here.
template <typename ... T>
class ConstructAll: public T...
{
public:
using ConstructorParms = int;
using BASES_T = ConstructAll<T...>;
ConstructAll(int){}
};
template <typename T>
class WithTemplate
{
};
class WithoutTemplate
{
};
template <typename X>
class CircuitFromNetlist
{
private:
class SerialReader: public ConstructAll<
WithTemplate<X> // use this-> don't compile
//WithoutTemplate // but this works
>
{
public:
SerialReader( typename BASES_T::ConstructorParms p): BASES_T( p ) {}
};
public:
CircuitFromNetlist()
{
SerialReader ser{1};
}
};
int main()
{
CircuitFromNetlist<int> c;
}
If I use WithTemplate<X>it did not compile and runs into:
main.cpp:31:40: error: 'BASES_T' has not been declared
SerialReader( typename BASES_T::ConstructorParms p): BASES_T( p ) {}
^~~~~~~
main.cpp: In constructor 'CircuitFromNetlist::SerialReader::SerialReader(int)':
main.cpp:31:70: error: class 'CircuitFromNetlist::SerialReader' does not have any field named 'BASES_T'
SerialReader( typename BASES_T::ConstructorParms p): BASES_T( p ) {}
If I flip the code to use non templated class it seems to work.
Some idea to get the thing working?
What you're seeing here is actually correct behavior according to the C++11 standard:
In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. -- [temp.dep] (emphasis mine)
When you inherit from ConstructAll<WithoutTemplate>, the base class does not depend on the template parameter X, but obviously inheriting from ConstructAll<WithTemplate<X>> the base class does depend on this template parameter.
You will have to explicitly refer to the type as typename ConstructAll<WithTemplate<X>>::BASES_T.
There are 2 different specialization template forms in c++
One is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
The other is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
They can also be compiled in VS2013. I notice that the second implementation of specialization template situation is just lack of template<>
I want to know what the difference is between the 2 forms above.
Visual C++ is wrong.
The standard is very clear about this.
First,
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax.
Meaning that, for explicit specialization of a class template, the member definition strictly do not require template<>.
Example:
template<class T>
struct A {
};
template<>
struct A<int> {
void f(int);
};
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { / ... / }
And,
A member or a member template of a class template may be explicitly
specialized for a given implicit instantiation of the class template,
even if the member or member template is defined in the class template
definition. An explicit specialization of a member or member template
is specified using the syntax for explicit specialization.
Meaning that, for a template that is not "explicit specialized", you can specialize its member, with the template<> (syntax for explicit specialization)
Example,
template<class T>
struct A {
void f(T);
};
// specialization
template<>
void A<int>::f(int);
The above examples are directly copied out from standard. To summarize, if the class is already explicitly specialized, do not use template<>, else if the class relies on implicit instantiation, use template<>.
Your first example compiles fine in Clang, and your second example fails to compile in Clang, you will get an error:
error: template specialization requires 'template<>'
template <class T> class mycontainer { ... };
template <> class mycontainer <char> { ... };
The first line is the generic template, and the second one is the specialization.
When we declare specializations for a template class, we must also define all its members, even those identical to the generic template class, because there is no "inheritance" of members from the generic template to the specialization.
http://www.cplusplus.com/doc/tutorial/templates/
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 <>.
just now I had to dig through the website to find out why template class template member function was giving syntax errors:
template<class C> class F00 {
template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here
I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:
f.template bar<T>();
what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?
I got tripped up the first time I inherited a templated class from another templated class:
template<typename T>
class Base {
int a;
};
template<typename T>
class Derived : public Base<T> {
void func() {
a++; // error! 'a' has not been declared
}
};
The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:
template<typename T>
class Derived : public Base<T> {
using Base<T>::a;
void func() {
a++; // OK!
}
};
Alternatively, you can make it explicit that you are using a member of T:
void func {
T::a++; // OK!
}
This one got me upset back then:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write
f.foo::vector<int>();
GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:
"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
template "foo::vector" (declared at line 8) used in preference to
class template "std::vector" (declared at line 163 of
"stl_vector.h")
f.vector<int>(); // ambiguous!
The star of questions about templates here on SO: the missing typename!
template <typename T>
class vector
{
public:
typedef T * iterator;
...
};
template <typename T>
void func()
{
vector<T>::iterator it; // this is not correct!
typename vector<T>::iterator it2; // this is correct.
}
The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.
The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.
template <typename T>
void func()
{
T::staticTemplateFunc<int>(); // ambiguous
T::template staticTemplateFunc<int>(); // ok
T t;
t.memberTemplateFunc<int>(); // ambiguous
t.template memberTemplateFunc<int>(); // ok
}
Out of scope class member function definition:
template <typename T>
class List { // a namespace scope class template
public:
template <typename T2> // a member function template
List (List<T2> const&); // (constructor)
…
};
template <typename T>
template <typename T2>
List<T>::List (List<T2> const& b) // an out-of-class member function
{ // template definition
…
}