My problem can be resumed by the following piece of code:
template <typename T> struct C2;
template <typename T>
struct C1
{
template <typename Type,
template <typename Ti> class Container = C2>
void m() {}
};
template <typename T>
struct C2
{
template <typename Type = int,
template <typename Ti> class Container = C2> // <-- Here is the problem!
void m() {}
};
The gnu compiler, version 4.8.1 fails with the following message:
test-temp.C:16:47: error: invalid use of type ‘C2<T>’ as a default value for a template template-parameter
template <typename Ti> class Container = C2>
It refers to default template parameter C2 for the the method C2::m.
Apparently (it is my opinion), the compiler is seeing C2<T> as default parameter instead of C2 (without <T>). So, when it finds the instruction it fails because type C2<T> does not match with Container.
However, clang++, just for exactly the same code, compiles fine!
My questions:
Which compiler has the truth?
Is there some alternative for expressing the same sense with the current version of gnu compiler?
Thanks in advance
Leandro
I think Clang is correct, and g++ is in error, quote from the draft Standard (bold emphasis is mine)
14.6.1 Locally declared names [temp.local]
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 <>.
You can use the :: scope resolution operator to beat g++ into submission
template <typename T>
struct C2
{
template <typename Type = int,
template <typename Ti> class Container = ::C2>
// ^^ <-- here is the solution!
void m() {}
};
Live Example.
So does the 14.6.1 reference in TemplateRex's answer mean that G++ is correct (and Clang and VC++ are wrong) to accept this, since it uses X as the template argument to a template template parameter?
template< template< typename > class T >
class factory { };
template< typename T >
class X
{
friend class factory< X >; // ***
};
int main()
{
}
In this example G++ treats X as the name of the class template, whereas Clang and VC++ treat it as the injected class name.
Edit: Clang 5.0.0 now accepts the code, the same as G++ and EDG.
Related
I encountered a very strange compiler error. For some reason the posted code does compile properly with g++ (7.3.0) while clang (7.0.0) fails:
../TemplateAlias/main.cpp:64:9: error: no matching function for call to 'freeFunc'
freeFunc(new Func, dummyField);
^~~~~~~~
../TemplateAlias/main.cpp:73:12: note: in instantiation of member function 'Helper<Traits<double, ConcreteData, ConcreteField> >::func' requested here
helper.func();
^
../TemplateAlias/main.cpp:21:13: note: candidate template ignored: deduced conflicting templates for parameter '' ('FieldData' vs. 'ConcreteData')
static void freeFunc(SomeFunc<T, FieldData>* func,
^
Both compiler options were set to -std=c++14
template<typename T>
struct ConcreteData
{
T data;
};
template<typename T, template<typename U> class FieldData>
struct ConcreteField
{
FieldData<T> someMember;
};
template<typename T, template<typename U> class FieldData>
struct SomeFunc
{
};
template<typename T, template<typename U> class FieldData>
static void freeFunc(SomeFunc<T, FieldData>* func,
ConcreteField<T, FieldData>& field)
{
// apply the func on data
(void)field; // silence compiler warning
delete func;
}
template<
typename ScalarType,
template<typename U> class FieldDataType,
template<typename U, template <typename X> class Data> class FieldType
>
struct Traits
{
using Scalar = ScalarType;
template<typename T>
using FieldData = FieldDataType<T>;
using Field = FieldType<Scalar, FieldDataType>; // fails with clang only
// using Field = FieldType<Scalar, FieldData>; // using this line helps clang
};
template<typename Traits>
struct Helper
{
// alias all types given by trait for easier access
using Scalar = typename Traits::Scalar;
using Field = typename Traits::Field;
template<typename U>
using DataAlias = typename Traits::template FieldData<U>;
void func()
{
// using Func = SomeFunc<Scalar, DataAlias>; // this line is intended, but fails with both GCC and clang
using Func = SomeFunc<Scalar, Traits::template FieldData>; // compiles only with GCC, fails with clang
Field dummyField;
freeFunc(new Func, dummyField);
}
};
int main()
{
using ConcreteTraits = Traits<double, ConcreteData, ConcreteField>;
Helper<ConcreteTraits> helper;
helper.func();
return 0;
}
According to cppreference.com:
A type alias declaration introduces a name which can be used as a
synonym for the type denoted by type-id. It does not introduce a new
type and it cannot change the meaning of an existing type name. There
is no difference between a type alias declaration and typedef
declaration. This declaration may appear in block scope, class scope,
or namespace scope.
and
Alias templates are never deduced by template argument deduction when
deducing a template template parameter.
In my understanding both types (ConcreteData and FieldData) should be equivalent. Why is clang failing in this condition and why do both compiler fail when using the "second stage" alias? Which compiler is right according to the C++ standard? Is it a compiler bug or a subtle ambiguous interpretation of the C++14 standard?
Borrowing the minimal example of #Oktalist.
template <typename>
class T {};
template <typename _>
using U = T<_>;
template <template <typename> class X>
void f(A<X>, A<X>) {}
if you replace f by:
template <template <typename> class X, template <typename> class Y>
void f(A<X>, A<Y>) {}
the code no longer fail to compile. You can see that the problem is about equivalence of template parameters X and Y, they are deduced to different types.
The equivalence of types produced by alias template are only considered when referring to specialization of the alias, as is specified on [temp.alias]/2:
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template
Using this rule and the rules for equivalence [temp.type]/1:
T<int> and U<int> are equivalent, so are X<T<int>> and Z<U<int>>, but this rule doesn't extend to the alias template U being equivalent to the class template T (by themselves, they aren't specializations).
This is the same scenario for the alias FieldData and the class template ConcreteData.
There are in fact two defect report, CWG-1286 and CWG-1244 that propose the equivalence extension for alias templates.
Source
In the following cases, the injected-class-name is treated as a template-name of the class template itself:
it is followed by <
it is used as a template argument that corresponds to a template template parameter
it is the final identifier in the elaborated class specifier of a friend class template declaration.
So I tried to examine all 3 cases (additionally in context of base ambiguity though I think it shouldn't matter here).
The first case seems simple.
The question is - why don't commented out examples work? They don't on both GCC & Clang so I don't think it's an implementation issue
template <template <class> class> struct A;
template <class T> struct Base {};
template <class T> struct Derived: Base<int>, Base<char>
{
// #1
typename Derived::Base<double> d;
// #2
// using a = A<Base>;
using a = A<Derived::template Base>;
// #3
template<class U1>
friend struct Base;
// template<class U>
// friend struct Derived::template Base;
};
Are the rules above only for template itself, not for bases? If so, what are rules for bases, especially for the last 2 of the cases?
The relevant rule here is [temp.local]/4:
A lookup that finds an injected-class-name ([class.member.lookup]) can result in an ambiguity in certain cases (for example, if it is found in more than one base class). If all of the injected-class-names that are found refer to specializations of the same class template, and if the name is used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous. [ Example:
template <class T> struct Base { };
template <class T> struct Derived: Base<int>, Base<char> {
typename Derived::Base b; // error: ambiguous
typename Derived::Base<double> d; // OK
};
— end example ]
Which I think means that this is a gcc and a clang bug. In:
using a = A<Base>;
All of the injected-class-names that are found do refer to specializations of the same class template (Base<T>) and the name is used as a template-name (because it's a template argument for a template template parameter), so this should just refer to the class template itself and not be ambiguous.
Consider the following code which uses "template template" parameters to instantiate a class template using multiple types:
#include <iostream>
using namespace std;
enum E
{
a = 0,
b = 1
};
template <template <E> class Action, class T>
void do_something(const T& value)
{
typedef Action<a> type1;
typedef Action<b> type2;
}
template <E e, class Enable = void>
class Foo
{
};
int main()
{
do_something<Foo>(int(55));
}
Using an older compiler (GCC 4.1.2), the above code compiles fine. However, using a newer compiler (GCC 4.4.6 or 4.8.1), the following error is produced:
test3.cpp:25:27: error: no matching function for call to ‘do_something(int)’
do_something<Foo>(int(55));
So it looks like GCC can't bind to do_something, because the template template parameters only declare a single parameter (an Enum), but Foo actually takes two template parameters (even though one is default.) I guess GCC 4.1.2 allowed the default parameter to be ignored.
Okay, so if I change the template definition to:
template <template <E, class> class Action, class T>
void do_something(const T& value)
{
typedef Action<a> type1;
typedef Action<b> type2;
}
...then no version of GCC I tested will compile it. They all produce a similar error:
test3.cpp:13: error: wrong number of template arguments (1, should be 2)
test3.cpp:10: error: provided for ‘template<E <anonymous>, class> class Action’
So now, the compiler complains because the expression typedef Action<a> type1 only provides a single template parameter. Apparently, I'm not able to implicitly use the default parameter here.
Is there some way I can use the default parameter of a template in a template template function?
Default arguments are ignored for parameters of template arguments. There's this example in n3337, chapter [temp.arg.template], paragraph 2:
template<class T> class A { /∗ ... ∗/ };
template<class T, class U = T> class B { /∗ ... ∗/ };
template <class ... Types> class C { /∗ ... ∗/ };
template<template<class> class P> class X { /∗ ... ∗/ };
template<template<class ...> class Q> class Y { /∗ ... ∗/ };
X<A> xa; // OK
X<B> xb; // ill-formed: default arguments for the parameters of a template argument are ignored
X<C> xc; // ill-formed: a template parameter pack does not match a template parameter
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK
Note the comment at X<B> xb; above. I can't find the normative text, I'm afraid.
You can correlate this with functions - default arguments are not a part of a signature, either. The same thing would also happen if you tried to call a function that has a parameter defaulted through a function pointer.
With a using template alias, a new feature in C++11, you can create a one-parameter template that is equivalent to another template that has two parameters, one of which is defaulted.
template <E e> using Foo1 = Foo<e>;
This creates Foo1, a one-parameter template, even though Foo technically has two arguments, one of which is defaulted. You can use it as:
do_something<Foo1>(int(55));
Alternatively, if C++11 features such as using are not available, then you scan specify the default in your declaration of do_something. This means then, unfortunately, that do_something can no longer deal with simple one-arg templates. Hence, I think the using method above is better.
template <template <E, class = void> class Action, class T>
void do_something(const T& value);
If you take this approach, putting the default in the args to do_something, then this default takes precedence over the default specified at the declaration Foo. This is based on my experiments, and I can't comment with confidence on what is, and is not, standard. But I do think the using trick is fully standards-compliant regarding C++11.
(Ubuntu clang version 3.0-6ubuntu3)
I've got a templated class having two template paramters
template <class T, class U> class A /* ... */
and another template class that accepts a template class with two arguments as template parameter.
template <class T, class U, template<class X, class Y> class Z>
class B
{
typedef typename Z<T,U>::pointer pointer;
};
Is it impossible to create an instance of B in A where Z is A?
template <class T, class U>
class A
{
public:
B<T,U,A> foo (void) // compiler complaining here
{
B<T,U,A> test; // and here
return test;
}
};
A free function doing the same thing isn't problematic at all.
template<class T, class U>
B<T, U, A> bar (void)
{
B<T,U,A> test;
return test;
}
In other words: Is there any rule I didn't fell over yet that prevents me from using the name of the class I am in as a template argument?
The code is:
template <class T, class U, template<class X, class Y> class Z>
class B
{
typedef typename Z<T,U>::pointer pointer;
};
template <class T, class U>
class A
{
public:
B<T,U, A> foo (void)
{
B<T,U,A> test;
return test;
}
};
template<class T, class U>
B<T, U, A> bar (void)
{
B<T,U,A> test;
return test;
}
int main (void)
{
return 0;
}
And the MSVC 2012 compiler gives a Compiler Error 3200.
'A<T,U>' : invalid template argument for template parameter 'Z', expected a class template
Your compiler, MSVC, seems to follow the general rule laid down in §14.6.2.1/1 C++11:
A name refers to the current instantiation if it is, [...] in the definition of a class template, [...] the injected-class name [...] of the class template [...]
Inside the definition of class template A, the name A can be used because it is "injected" into the local (class) scope of A. Therefore, and famously, you can use A as well as A::A, as well as A::A::A and so on, to refer to A. By the rule quoted above, all of these expressions refer to the current instantiation (i.e. a specific type like A<int,float>), and not to the name of template A itself.
However, there is another rule, in §14.6.1/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 [...] as a template-argument for a template template-parameter [...] 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 that in C++03, there is no such exception for template template parameters; 14.6.1/1, in fact, is worded entirely differently. Under C++03, MSVC's interpretation of the rules was probably correct.)
Given the C++11 rule, however, in the member declaration
B<T,U,A> test;
inside the definition of A, the name A is clearly used as an argument for a template template parameter and therefore must be interpreted as template name, not as type name referring to the current instantiation.
However, it is not uncommon that compilers are confused in situations like this. There are two valid ways to tell them how to interpret A:
Using the so-called normal name ::A rather than the injected one:
B<T,U,::A> test;
This is possible because of §14.6.1/5 (which was 14.6.1/2c in C++03):
When the normal name of the template (i.e., the name from the enclosing scope, not the injected-class-name) is used, it always refers to the class template itself and not a specialization of the template. [...]
Using the injected one explicitly, but designating it as a template:
B<T,U,A::template A> test;
Both methods have been confirmed as solving this problem in MSVC.
If class A is defined before class B, I'm getting the error: 'B' does not name a type (in other words, B is not defined yet). Is this the error you are getting? It can be fixed either by placing B in front of A, or, if the two are referencing each other, by forward-declaring class B before A like this:
template <typename T, class U, template<typename X, class Y> class Z> class B;
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.