I have this simple code:
template<template <class> class Generator>
class TestHelper {};
template<class Writer>
class Test
{
typedef TestHelper< Test > Helper;
};
It's works great on last g++ versions, but, in 4.4 or 4.5, I get this error:
test.cpp:7: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class Generator> class TestHelper'
test.cpp:7: error: expected a class template, got 'Test<Writer>'
What I'm doing wrong?
It's because inside the body of class Test<Writer>, naming Test without providing the template arguments automatically assumes the same arguments (e.g. Writer).
For example, this allows you to write the copy constructor as:
Test(const Test&);
instead of
Test::Test(const Test<Writer>&);
You can overcome this by qualifying Test with its namespace, e.g.
typedef TestHelper< ::Test > Helper;
NOTE: As Tomalek suggests, the original usage is valid in C++0x. Here is the relevant paragraph of the standard (emphasis mine), from section 14.6.1 ([temp.local]):
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). 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 <>.
#Ben is probably right, but here's a totally different way to get it to compile, that doesn't use templates as args to templates.
template<class Generator> // changed this to a simpler template
class TestHelper {};
template<class Writer>
class Test
{
typedef TestHelper< typename Test :: Writer > Helper; // 2nd change
};
I made two changes. #Hugo, maybe this is what you wanted, and maybe this is what older versions of g++ did?
It's easy to get code to compile, but that doesn't mean that it does what you think it does!
Related
I have a class template inside of another class template. The inner class has a static data member. I am struggling to provide a definition for it. The below example works in clang 3.8 but not in gcc-7.1
template <typename T>
struct Out {
template <typename U>
struct In {
static int var;
};
};
template <typename T>
template <typename U>
int Out<T>::template In<U>::var;
gcc gives the error:
error: template definition of non-template ‘int Out<T>::In<U>::var’
int Out<T>::template In<U>::var;
^~~
What do I gotta do to make gcc happy?
Edit: turns out getting rid of template make this work:
template <typename T>
template <typename U>
int Out<T>::In<U>::var;
Which still leaves the question, is template allowed here?
This type of definition would more commonly be seen without the template before In. The template keyword is not needed here because Out<T>::In is a "member of the current specialization".
For the rule specifying when the template keyword is required before a member name, see [temp.names]/4. For the definition of the technical term "member of the current specialization", see [temp.dep.type]/4.
But the keyword is in fact allowed there, since the grammar permits it between any :: and name, and the semantics require only that the name that follows is either used with template arguments or names a class template ([temp.names]/5), and there are no other rules in the Standard to forbid it. And as a note in [temp.names]/5 explains:
[ Note: As is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the -> or . is not dependent on a template parameter, or the use does not appear in the scope of a template. - end note]
I'm getting compilation errors when trying to call the base class constructor in derived initialization list when using a template template parameter with CRTP.
Problem can be replicated with this snippet of code:
template <template<class> class Derived, class T>
struct base
{
};
template <class T>
struct derived : public base<derived, T>
{
derived()
: base<derived, T>()
{ }
};
The offending error messsage:
bug.cpp:10:16: error: template argument for template template parameter must be a class template or type alias template
: base<derived, T>()
^
bug.cpp:10:11: error: expected class member or base class name
: base<derived, T>()
^
bug.cpp:10:11: error: expected '{' or ','
3 errors generated.
This problem only appears to happen on clang (3.4), not g++ (4.8, 4.7, 4.6). I'm compiling with -std=c++11 also.
This is the first time I've needed to use CRTP with template template parameter. Am I doing this okay and it's a problem with clang++ or not?
I've grown to trust clang++ error messages more than g++ of late!
Your code is legal.
From the C++11 Standard, section 14.6.1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). 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.
Looks like your version of clang is still implementing the old rule. Based on your additional comments, it might be doing so only in the ctor-initializer-list.
User David Rodríguez - dribeas provided a workaround for compilers that haven't fully implemented the C++11 injected-class-name rule. Use any name of the class that isn't unqualified, for example:
derived()
: base< ::derived, T >()
// ^^ qualified with global namespace
{ }
Some compilers may require this in the inheritance list also:
template <class T>
struct derived : public base< ::derived, T >
// ^^
Here's the scenario:
template <template <typename> class T, typename V>
struct parent {
void do_something();
};
template <typename V>
struct child : public parent<child, V> {
void do_something(V argument);
using parent<child, V>::do_something; // C3200: invalid template argument for template parameter 'IMPL', expected a class template
};
The above code fails to compile on the given line with the given error (MSVC 9.0). However if I write this instead, outside of the class definition for child:
template <typename V>
struct parent_identity_meta {
typedef typename parent<child, V> type; // no error!
};
I can now successfully do the following, within child:
using parent_identity_meta<V>::type::do_something;
I know there's a limitation (alleviated in C++11) that you can't typedef against a template, but I don't think that's what I'm running into here, otherwise the typedef in parent_identity_meta would fail. It seems like child refers to the template when not inside of its own class definition, and to the class being generated from within itself.
This is pretty understandable (having to write child<V> every single time would be painful); but is there any way to override this behaviour?
This is a place where C++03 and C++11 are different from each other. The relevant part of the standard is [temp.local]/1. In C++03, this states:
Like normal (non-template) classes, class templates have an injected-class-name (clause 9). The injected-class-name can be used with or without a template-argument-list. When it is used without a template- argument-list, it is equivalent to the injected-class-name followed by the template-parameters of the class template enclosed in <>. When it is used with a template-argument-list, it refers to the specified class template specialization, which could be the current specialization or another specialization.
This means that child (without any template arguments) refers to the specialization child<V>. In C++11, it was changed to:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). 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 <>.
Note in particular When it is used ... as a template-argument for a template template-parameter ... it refers to the class template itself.. This means that in C++11, your code would be correct.
This code:
template <class T>
class Foo {};
typedef Foo<void*> Bar;
template <class T>
class Foo<T*> : public Bar {};
// use Foo<int*> somewhere.
Compiles and works fine in MSVC 9.0, but doesn't compile in GCC 4.1.1 or GCC 4.3.4, with the error:
error: invalid use of undefined type 'class Bar'
Is this illegal C++ that MSVC accepts incorrectly, or a limitation of GCC?
Either way, how can I work around this get the desired behaviour: pointer specialisations of Foo that inherit from unspecialised Foo<void*>?
You cannot do that, except by writing the specialization for all T*, except when T is void. Otherwise, you will derive the class from itself, which for obvious reasons can't work.
Instantiating the primary class template for arguments that have an explicit or partial specialization is not possible. If you try to, by provoking an instantiation before the explicit or partial specialization is visible (note that your code did not provoke such an instantiation), your program is ill-formed, with no diagnostic being required (which effectively renders the behavior undefined).
To achieve the above work-around, you can use SFINAE
template <class T>
struct isnt_void { typedef void type; };
template<> struct isnt_void<void> { };
template <class T, class = void>
class Foo {};
template <class T>
class Foo<T*, typename isnt_void<T>::type> : public Foo<void*> {};
The typedef is a red herring.
The following code is equivalent:
template <class T>
class Foo {};
template <class T>
class Foo<T*> : public Foo<void*> {};
It should be clear that, although Foo<T*> is declared at this point, it is not defined. And thus you may not use it as a base.
[class.name] (2003 wording, 9.1/2):
A class definition introduces the class name into the scope where it is defined
[class.mem] (2003 wording, 9.2/2):
A class is considered a
completely-defined object type (3.9)
(or complete type) at the closing } of
the class-specifier. Within the class
member-specification, the class is
regarded as complete within function
bodies, default arguments and
constructor ctor-initializers
(including such things in nested
classes). Otherwise it is regarded as
incomplete within its own class
member-specification.
[class.derived] (2003 wording, 10/1):
The class-name in a base-specifier shall not be an incompletely defined class (clause 9);
A superior solution would be to compose of Foo<void*>. After all, you don't want the raw void* interface cluttering up your stuff, and you don't want a Foo<T*> to be convertible to a Foo<void*>.
Alternatively, you could fully specialize Foo<void*> beforehand.
Assuming, of course, that you're doing this for type folding, instead of because you actually want inheritance.
I'm porting my c++ windows code (msvc & intel) to Linux (g++). The code uses lots of templates (I like metaprogramming ;-). But I can't compile this code:
template <class TA>
struct A
{
template <class TAB> struct B;
};
template <class TC>
struct C {};
template <class TD>
struct D
{
template <class TTD> class T {};
};
template<class TA>
template<class TBA>
struct A<TA>::B : C<typename D<TA>::T<TBA> >
{
int foo;
};
g++ tells me that in definition of A::B, C class has invalid template arguments. But on msvc and intel it works well! What's the problem here?
PS: Sorry, I can't post the original code, because it's too template-complicated. But this example is virtually the same and gives the same error on g++.
Thank you.
UPDATE: I've found the problem is in TBA argument of T. g++ doensn't like usage of second template in the definition.
You need the template keyword
template<class TA>
template<class TBA>
struct A<TA>::B : C<typename D<TA>::template T<TBA> >
{
int foo;
};
GCC is correct to give a diagnostic here. This is because T cannot be looked up in the dependent scope D<TA>. The meaning of the < after it depends on whether T is a template or not. The Standard says that T shall be assumed to be not a template and thus T cannot be followed by a template argument list.
template is like typename in that it tells the compiler to treat T as a template and that the < is the start of an argument list in any case. The Standard says in paragraphs 14.2/2 and 14.2/4
For a template-name to be explicitly qualified by the template arguments, the name must be known to refer
to a template.
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
In your case, you have T appear after the nested-name-specifier D<TA> which depends on the template-parameter TA. For the typename-specifier to parse correctly, the construct D<TA>::T<TBA> must interpret T as the name of a class template, which 14.2 forbids.
On that topic, it's always a good idea to try and compile with Clang
main1.cpp:21:37: error: use 'template' keyword to treat 'T' as a dependent template name
struct A<TA>::B : C<typename D<TA>::T<TBA> >
^
template
1 error generated.