Injected class name as type - c++

Given the following code,
template <class> using void_t = void;
template <class C, class = void> struct X { enum { v = 0 }; };
template <class C> struct X<C, void_t<typename C::T> > { enum { v = 1 }; };
struct T { };
int main() { return X<T>::v; }
what should main return? GCC and MSVC say 1, Clang says 0.

I think Clang is right here. The rule in [class.qual] is:
In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:
if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C ([class]), or
[... irrelevant here ...]
the name is instead considered to name the constructor of class C. [ Note: For example, the constructor is not an acceptable lookup result in an elaborated-type-specifier so the constructor would not be used in place of the injected-class-name. — end note ] Such a constructor name shall be used only in the declarator-id of a declaration that names a constructor or in a using-declaration. [ Example:
struct A { A(); };
struct B: public A { B(); };
A::A() { }
B::B() { }
B::A ba; // object of type A
A::A a; // error, A​::​A is not a type name
struct A::A a2; // object of type A
— end example ]
typename C::T is the same kind of thing as A::A, it's lookup in which function names are not ignored (typename doesn't cause function names to be ignored). So, in typename C::T, when C is T, the name T is considered to name the constructor. As it's not a type name, we should get a substitution failure and fallback to the primary template.
Filed 86818.

To complete Barry's answer, typename only says to the compiler that the following name is a type for the analysis performed before template instatiation. After instantiation, name look up is performed as if typename was not there, [temp.res]/4:
The usual qualified name lookup is used to find the qualified-id even in the presence of typename.
So Clang is right. In order to get a consistent compiler behaviour you can use the elaborated type specifier struct C::T in place of typename C::T:
template <class> using void_t = void;
template <class C, class = void> struct X { enum { v = 0 }; };
template <class C> struct X<C, void_t<struct C::T> > { enum { v = 1 }; };
struct T { };
int main() { return X<T>::v; }

Related

Error when passing template parameters to inner structure

I try to compile the following C++ code:
struct A {
template< bool x >
bool fun() {
return x;
}
};
template< typename T >
struct B {
struct A2 {
template< bool x >
bool fun() {
return x;
}
};
void test() {
A a;
A2 a2;
a.fun< true >();
a2.fun< true >();
}
};
The compiler complains that:
source_file.cpp: In member function ‘void B<T>::test()’:
source_file.cpp:22:24: error: expected primary-expression before ‘)’ token
a2.fun< true >();
^
However the line just above (a.fun< true >()) compiles just fine. Interestingly, if I remove the line template< typename T >, then compilation succeeds. However that line is required for reasons that do not appear from the minimal (not) working example. What is wrong here?
In this context A2 is actually a shorthand for B<T>::A2. Since A2 is a type dependent on the template parameter T, you have to refer to its member templates with an explicit template keyword
a2.template fun< true >();
A is not a dependent type and its member templates can be referred to with "plain" syntax without that extra template keyword.
See 14.2/4 and a similar example there
14.2 Names of template specializations [temp.names]
4 When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.
Otherwise the name is assumed to name a non-template. [ Example:
struct X {
template<std::size_t> X* alloc();
template<std::size_t> static X* adjust();
};
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
—end example ]

Class template with one parameter and default value

I must be missing something obvious here because this really came to me as a surprise.
The following code gives me the error: error: missing template arguments before ‘a’
template<int n=0>
class A {};
...
A a;
...
Is there a reason why a template with 1 parameter declared with a default value has to be instantiated specifying a value for it?
Can someone quote the standard?
A is still a template class. But you can omit the template parameter though:
template<int n=0>
class A {};
int main() {
A<> a;
// ^^
return 0;
}
See the live demo.
I think1 the relevant standard section is here
14.7 Template instantiation and specialization
...
3 An explicit specialization may be declared for a function template, a class template, a member of a class
template or a member template. An explicit specialization declaration is introduced by template<>. 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. In the explicit specialization declaration for a function template or a member function template, the name of the function
or member function explicitly specialized may be a template-id.
[Example:
template<class T = int> struct A {
static int x;
};
template<class U> void g(U) { }
template<> struct A<double> { }; // specialize for T == double
template<> struct A<> { }; // specialize for T == int
template<> void g(char) { } // specialize for U == char
// U is deduced from the parameter type
template<> void g<int>(int) { } // specialize for U == int
template<> int A<char>::x = 0; // specialize for T == char
template<class T = int> struct B {
static int x;
};
template<> int B<>::x = 1; // specialize for T == int
— end example ]
1)Sorry, I can't find a better standard cite / example. It doesn't cover exactly the OP's case, but demonstrates at least the same, that templates still need the <> angle brackets to be identified as templates (classes or functions).
possible workaround if it's important to disguise the nature of your object:
// the template class
template<int n=0>
class ReallyA {};
// an alias for the common case
using A = ReallyA<0>;
A a;
This is how the standard library defines std::string, for example.
using string = basic_string<char>;

Should a class-member using-declaration with a dependent qualified-id be a dependent name?

Draft N3337 of the C++11 standard states in [namespace.udecl]
A using-declaration introduces a name into the declarative region in which the using-declaration appears.
Every using-declaration is a declaration and a member-declaration and so can be used in a class definition.
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the
class being defined.
This is generally used to make a protected typedef within a base-class public in the derived class, as in the following example, which compiles successfully in the latest version of Clang:
struct A
{
protected:
typedef int Type;
};
struct B : A
{
using A::Type;
};
B::Type x;
The using-declaration can refer to a template class. This compiles:
struct A
{
protected:
template<typename T>
struct Type
{
};
};
struct B : A
{
using A::Type;
};
B::Type<int> x;
It's also possible to refer to a template in a dependent base-class. The following compiles successfully (with the typedef commented.)
template<typename T>
struct A
{
protected:
template<typename U>
struct Type
{
};
};
template<typename T>
struct B : A<T>
{
using /* typename */ A<T>::Type; // A<T> is dependent, typename required?
// typedef Type<int> IntType; // error: unknown type name 'Type'
};
B<int>::Type<int> x;
Uncommenting the typename causes an error when instantiating B<int>: "error: 'typename' keyword used on a non-type".
Uncommenting the typedef causes an error when parsing B before its first instantiation. I'm guessing this is because the compiler does not treat Type as a dependent type-name.
The last paragraph of [namespace.udecl] suggests that using-declarations may specify dependent names, and that the typename keyword must be used in order to disambiguate further usage of the name introduced:
If a using-declaration uses the keyword typename and specifies a dependent name (14.6.2), the name introduced
by the using-declaration is treated as a typedef-name
My reading of [temp.dep] suggests that A<T>::Type is a dependent name. It follows logically that the name introduced by the using-declaration should also be dependent, but [temp.dep] does not explicitly mention the case of a dependent using-declaration. Am I missing something?
The problem is that Type is not a class, but a class template. You can do the following (this way you tell the compiler that Type is a class template in scope of B):
template<typename T>
struct B : A<T>
{
using A<T>::Type;
typedef typename B::template Type<int> IntType;
};
Actually, in your second example in order to write typedef for IntType you'd have to do the same.
Yes, a class-member using-declaration with a dependent qualified-id introduces a dependent name.
[namespace.udecl]
A using-declaration introduces a name into the declarative region in which the using-declaration appears.
If the name introduced is dependent, it stays dependent - I can find nothing to suggest otherwise.
However, the using-declaration syntax does not provide a way to specify that a dependent name is a template. Subsequent references to the dependent name Type within B may or may not refer to a template, so Type<int> cannot be parsed.
The following example demonstrates valid usage of a dependent using-declaration.
template<typename T>
struct A
{
protected:
struct Type
{
typedef int M;
};
};
template<typename T>
struct B : A<T>
{
using typename A<T>::Type;
typedef typename Type::M Type2;
};
B<int>::Type2 x;

How do I use the class-name inside the class itself as a template argument?

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;

Templates :Name resolution -->IS this statement is true while inheritance?

This is the statement from ISO C++ Standard 14.6/6:
Within the definition of a class template or within the definition of a member of a class template, the keyword typename is not required when referring to the unqualified name of a previously declared member of the class template that declares a type. The keyword typename shall always be specified when the member is referred to using a qualified name, even if the qualifier is simply the class template name. [Example:
template<class T> struct A {
typedef int B;
A::B b; // ill-formed: typename required before A::B
void f(A<T>::B); // ill-formed: typename required before A<T>::B
typename A::B g(); // OK
};
The keyword typename is required whether the qualified name is A or A<T> because A or A<T> are synonyms within a class template with the parameter list <T>. ]
Is this statement is true while inheritance?
If yes, can anyone explain this?
I checked with inner class; it is accepted? But I am unable to check with inheritance?
Yes, that is equally true of inherited members.
The keyword typename is required for members of base templates, but not base classes in general. The reason it is required for base templates is that their members are not automatically brought into the scope of the class {} block, so the only way to refer to them is with a qualified-id, which requires typename.
template< typename >
class base1
{ typedef int type1; };
class base2
{ typedef int type2; };
template< typename A >
class derived
: base1< A >, base2 {
typename base1< A >::type1 x;
type2 y;
};