Template disambiguator for dependent names - c++

I encountered the following problem by compiling the following example:
template <int N>
class Matrix {
public:
template <int Idx>
int head() {
return Idx;
}
};
template <typename T>
class Test {
static constexpr int RayDim = 3;
public:
int func() const {
Matrix<RayDim> yF;
return yF.head<1>();
// ^ is template keyword required here?
}
};
struct Empty {};
void test() {
Test<Empty> t;
}
Link to Compiler Explorer:
https://godbolt.org/z/js4XaP
The code compiles with GCC 9.2 and MSVC 19.22 but not with clang 9.0.0. Clang states that a template keyword is required. If static constexpr int RayDim = 3; is moved into int func() const clang accepts it.
As stated as a comment in the code block, is the template keyword required for yF.head<1>()?

The template keyword should not be required here, so clang is incorrect to reject the program.
All C++ Standard section and paragraph numbers and quotes below are the same for C++17 draft N4659 and the current linked C++20 draft.
The requirement for template after a . or -> or :: token when naming a member template is in [temp.names]/4. The paragraph first lists cases where the keyword is not allowed, then cases where it is optional and doesn't make a difference, then:
In all other contexts, when naming a template specialization of a member of an unknown specialization ([temp.dep.type]), the member template name shall be prefixed by the keyword template.
A "member of an unknown specialization" is a member of a dependent type which is not "the current instantiation". So the question is whether Matrix<RayDim> is a dependent type. For that, we look at [temp.dep.type]/9:
A type is dependent if it is
a template parameter,
a member of an unknown specialization,
a nested class or enumeration that is a dependent member of the current instantiation,
a cv-qualified type where the cv-unqualified type is dependent,
a compound type constructed from any dependent type,
an array type whose element type is dependent or whose bound (if any) is value-dependent,
a function type whose exception specification is value-dependent,
a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent or is a pack expansion, or
denoted by decltype(expression), where expression is type-dependent.
Matrix<RayDim> is clearly not a template parameter, any kind of member, cv-qualified, an array type, a function type, or specified by decltype. It is a compound type, but it uses only a template-name and an expression, so is not constructed from any other type.
That leaves the simple-template-id case. The template name Matrix is not a template parameter. The template argument RayDim is an expression, so now to see if it is type-dependent or value-dependent.
"Type-dependent" is defined in [temp.dep.expr]. Only paragraph 3 can apply to a lone identifier like RayDim:
An id-expression is type-dependent if it contains
an identifier associated by name lookup with one or more declarations declared with a dependent type,
an identifier associated by name lookup with a non-type template-parameter declared with a type that contains a placeholder type,
an identifier associated by name lookup with a variable declared with a type that contains a placeholder type ([dcl.spec.auto]) where the initializer is type-dependent,
an identifier associated by name lookup with one or more declarations of member functions of the current instantiation declared with a return type that contains a placeholder type,
an identifier associated by name lookup with a structured binding declaration whose brace-or-equal-initializer is type-dependent,
the identifier __func__ ([dcl.fct.def.general]), where any enclosing function is a template, a member of a class template, or a generic lambda,
a template-id that is dependent,
a conversion-function-id that specifies a dependent type, or
a nested-name-specifier or a qualified-id that names a member of an unknown specialization;
or if it names a dependent member of the current instantiation that is a static data member of type "array of unknown bound of T" for some T ([temp.static]).
RayDim certainly does not contain any __func__, template-id, conversion-function-id, nested-name-specifier, or qualified-id. Name lookup finds the class template's static member declaration. That declaration of RayDim is certainly not a template-parameter, a member function, or a structured binding declaration, and its type const int is certainly not a dependent type or array type and does not contain a placeholder type. So RayDim is not type-dependent.
"Value-dependent" is defined in [temp.dep.constexpr]. The only cases that can apply to a lone identifier like RayDim are in paragraph 2:
An id-expression is value-dependent if:
it is type-dependent,
it is the name of a non-type template parameter,
it names a static data member that is a dependent member of the current instantiation and is not initialized in a member-declarator,
it names a static member function that is a dependent member of the current instantiation, or
it is a constant with literal type and is initialized with an expression that is value-dependent.
From above, RayDim is not type-dependent. It is certainly not a template parameter or a member function. It is a static data member and dependent member of the current instantiation, but it is initialized in the member-declarator. That is, the "= 3" appears inside the class definition, not in a separate member definition. It is a constant with literal type, but its initializer 3 is not value-dependent.
So RayDim is not value-dependent or type-dependent. Therefore Matrix<RayDim> is not a dependent type, yF.head is not a member of an unknown instantiation, and the template keyword before head is optional, not required. (It is permitted since it's not in a "type-only context" and head does in fact name a member template.)

Disclaimer
this is not an answer, but rather a long comment
My language-lawyer skills are too low to fully understand the standard but here are a few things I discovered from experimenting with the code. Everything that follows is based on my (far from perfect) understanding of the matter and probably needs some reviews.
Investigation
First off, I went to a fully defined standard version (C++17) so we operate on a well defined implementation.
Looking at this code it seems like MSVC still has some problems (with its lookup, I guess?) when it comes to template instantiation and redefinition. I wouldn't trust MSVC that much in our scenario.
That beeing said, lets think about why we could need the template keyword at
return yF.template head<1>();
Dependent names
Sometimes, inside templates, we have to help the compiler decide whether a name refers to
a value int T::x = 0,
a type struct T::x {};, or
a template template <typename U> T::foo<U>();
If we refer to a value, we do nothing. If we refer to a type, we have to use typename. And if we refer to a template we use template. More on that subject can be found here.
I don't understand the standard specification when it comes to the actual definition of a dependent name but here are some observations.
Observations
Lets take a look at the reference code
template <int N>
struct Matrix
{
template <int Idx>
int head() { return Idx; }
};
template <typename T>
struct Test
{
static constexpr int RayDim = 3;
int func() const
{
Matrix<RayDim> yF;
return yF.head<1>(); // clang complains, gcc and msvc are ok
}
};
struct Empty {};
int test()
{
Test<Empty> t;
return t.func();
}
Usually RayDim should be a dependent name (because it's inside the template Test) which would cause Matrix<RayDim> to be a dependent name aswell. For now, lets assume that Matrix<RayDim> actually is a dependent name. This makes Matrix<RayDim>::head a dependent name aswell. Since Matrix<RayDim>::head is a templated function it is a template in itself and the rules of dependent names from above apply, requiring us to use the template keyword. This is what clang is complaining about.
However, since RayDim is defined inside Test and func is also defined inside the same template and not a templated function in itself, I don't think RayDim actually is a dependent name in the context of func. Furthermore, RayDim doesn't rely on the template arguments of Test. In this case, Matrix<RayDim> and Matrix<RayDim>::head respectively, would become non-dependent names, which allows us to omit the template keyword. This is why gcc (and msvc) compile.
If we were to template RayDim aswell, like here
template <typename>
static constexpr int RayDim = 3;
gcc would treat it as a dependent name aswell (which is correct, since there might be a template specialization later so we don't know at that point). Meanwhile, msvc happily accepts everything we throw at it.
Conclusion
It seems like it's boiling down to whether RayDim is a dependent name in the context of Test<T>::func or not. Clang thinks it is, gcc doesn't. From some more test it looks like msvc sides with clang on this one. But it's also kinda doing it's own thing, so who knows?
I would side with gcc here as I see no possible way of RayDim becoming dependent at the point where func is instantiated.

Related

Is it a defect in the standard about dependent name resolution for template

About how lookup the dependent name for template, The standard only gives a little sentence like this, there's no more:
In resolving dependent names, names from the following sources are considered:
Declarations that are visible at the point of definition of the template.
Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
Consider the below code
struct Test{
using type = int;
};
// #1
template<typename T>
struct TMP{
using type = typename T::type;
};
int main(){
TMP<Test>::type v = 0;
}
For this code, the name type indeed a dependent name because T is a template parameter and here is not a function call, So, the only relevant bullet point is Number 1. It only says the dependent name shall be visible before the template definition, It means in my code, the declaration shall be visible at #1. In actually, typename T::type is a qualified-id, hence qualified name lookup rules apply to it and because T is a template parameter, So the lookup action shall be occurred after given a template argument, namely, during the instantiation of a specialization for such a template. But the quote I cited does not say anything about this. So, I wonder Is it a defect in the standard? If I miss anything that interpret this in the standard, please cite them for this question.
To complete language-lawyer comments, in §"Unknown specializations" of this page
Within a template definition, certain names are deduced to belong to
an unknown specialization, in particular,
a qualified name, if any name that appears to the left of :: is a dependent type that is not a member of the current instantiation
...
In your struct TMP,
the type T is indeed a dependent type
the expression typename T::type is a qualified name and the left if :: is a dependent type
that expression becomes an unknown specialization
Then it is said:
Members of unknown specialization are always dependent, and are looked up and bound at the point of instantiation as all dependent names
which allows the lookup of TMP<Test>::type at the point of instanciation.

Name lookup for members of the current instantiation and members of unknown specializations

Does any wording specify how the names of members of unknown specializations and of the current instantiation are looked up? [temp.res] p10 has a very informal definition:
When looking for the declaration of a name used in a template definition, the usual lookup rules are used for non-dependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known.
[temp.dep] p2 specifies that dependent names only apply to unqualified-id's in function calls with type-dependent parameters, so going strictly from this definition, all other names would be non-dependent, which would not makes sense for something like this:
template<typename B>
struct A : B
{
void f()
{
this->a += 1; // a here is a member of an unknown specialization, but is not a dependent name
}
};
Here, lookup would have to be postponed until a specialization is instantiated, however, there is no such wording that specifies this that I have found because a is not a dependent name.
The only explanation I can think of for this is that the definition dependent name differs from "a name that depends on template parameters". Even then, its not defined what it would mean for a name to depend on a template parameter.
As for members of the current instantiation, there is also no wording specifying when they are looked up and bound. For example:
template<typename T>
struct S
{
T a;
void f()
{
++a; // a is a member of the current instantiation, but not a dependent name
}
};
Lookup and binding in this case would not need to be postponed until a specialization is instantiated, as name hiding rules would ensure that a would always refer to the member a, or another more local name that was declared within the template definition. However, as with the previous case, there is no such wording that actually specifies what would happen in this case either. Certainly, the type of a would be dependent on a template parameter, but the actual meaning is easily deduced, as a function cannot acquire its type from a dependent type.
Is this just a defect in the standard?

When can `typename` be used with identifiers that unambiguously refer to a type?

Normally, typename is used to disambiguate between cases where an identifier may refer to a type, or may refer to something else:
template<class T>
void foo(typename T::type value) {
// ...
}
When can typename be used when an identifier is already a type?
1. Can it be used if there's already a class with this name?
class MyClass{};
void foo(typename MyClass value) {}
2. Can it be used with a template parameter that's declared as a type?
template<class T>
void foo(typename T value) {}
3. Can it be used with inner classes that are unambiguously types?
class A {
public:
class B {};
};
// Compiles; no typename necessary
void foo(A::B value) {}
// This compiles too on gcc and msvc
void bar(typename A::B value) {}
Compiler interpretation
Case 1: MSVC considers this OK; gcc and clang throw an error
Case 2: MSVC considers this OK; gcc and clang throw an error
Case 3: A::B is unambiguously a type, but gcc and clang now permit the use of typename.
The keyword typename is only permitted by the C++ syntax to introduce a template type parameter, or before a qualified name, i.e. something containing the :: token.
So your #1 and #2 are ill-formed because MyClass and T are unqualified names, not containing any ::.
Before a qualified name, the typename token is:
not allowed by the grammar before a base class name in the head of a class definition, or in combination with the class, struct, or union keywords; a qualified name is always treated as a type in these contexts
otherwise required, if the qualified name is dependent and a member of an unknown specialization
otherwise optional, whether within a template declaration or not
C++17 [temp.res]/3,5,6:
When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. ...
A qualified name used as the name in a class-or-decltype (Clause [class.derived]) or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the typename keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of the typename keyword. [Note: The typename keyword is not permitted by the syntax of these constructs. - end note]
If, for a given set of template arguments, a specialization of a template is instantiated that refers to a qualified-id that denotes a type or a class template, and the qualified-id refers to a member of an unknown specialization, the qualified-id shall either be prefixed by typename or shall be used in a context in which it implicitly names a type as described above.
So your #3 is well-formed, even though the name does not depend on a template parameter and isn't even in a template declaration.
Note C++20 will add many more contexts where typename is optional even with a dependent name, because it's possible to unambiguously determine from the contexts that the name can only mean a type.
From cppreference
Usage:
In a template declaration, typename can be used as an alternative to class to declare type template parameters and template template parameters (since C++17).
Inside a declaration or a definition of a template, typename can be used to declare that a dependent name is a type.
Inside a requirements for type requirements (since C++20)
So I would say that you have no guaranties that case 1 and case 2 will compile. As they do not fall into any of these three usage cases.
And for case 3, let's see what cppreference has to say about that:
The keyword typename may only be used in this way before qualified names (e.g. T::x), but the names need not be dependent.
The keyword typename must only be used in template declarations and definitions and only in contexts in which dependent names can be used. This excludes explicit specialization declarations and explicit instantiation declarations.(until C++11)
The keyword typename can be used even outside of templates. (since C++11)
So as there is no template in your example, case 3 should be guarantied to work only since C++11
And indeed a test program compiled OK with g++ -std=c++11 but issued this warning without -std=c++11
warning: 'typename' occurs outside of a template
[-Wc++11-extensions]

Is a function type dependent if it depends only on its own template parameters?

I came across an inconsistency in the way current C++ compilers (clang/gcc) determine whether a name is dependent. In the following example, A::f is dependent but ::f is not, resulting in an error when the latter is used.
template<typename>
struct B
{
typedef int Type;
};
template<typename U>
static U f(U u);
template<typename T>
struct A
{
template<typename U>
static U f(U u);
typename B<decltype(f(0))>::Type m1; // typename required
B<decltype(::f(0))>::Type m2; // typename not required
};
The inconsistent part is that the declaration of A::f does not depend on a template parameter of A, meaning it seems unnecessary to treat it as a dependent name.
This behaviour seems to be covered by the following wording in the C++11 standard:
[temp.dep.expr]/3
An id-expression is type-dependent if it contains
an identifier associated by name lookup with one or more declarations declared with a dependent type
[temp.dep.type]/3
A type is dependent if it is
a compound type constructed from any dependent type
The declaration of ::f is clearly not dependent, as its type depends only on its own template parameters. Why should A::f be treated differently?
I think that based on the standard, f is non-dependent, actually.
14.6.2.2 Type-dependent expressions [temp.dep.expr]
3 An id-expression is type-dependent if it contains
an identifier associated by name lookup with one or more declarations declared with a dependent type,
This applies equally to the global template function as it does to the member template function: not at all. The return type of U is dependent inside the definitions of the template functions, but for the caller, the function type of f<int> has already been transformed from U(U) to int(int). At any rate, it wouldn't explain why compilers treat the two cases differently, and it also would not explain why a non-template member function is also treated as dependent.
a template-id that is dependent,
a conversion-function-id that specifies a dependent type, or
These do not apply. There is no < or > that must always be present in a template-id, and there is no conversion function being called.
a nested-name-specifier or a qualified-id that names a member of an unknown specialization;
See below.
or if it names a static data member of the current instantiation that has type "array of unknown bound of T" for some T (14.5.1.3).
This also does not apply: there are no arrays involved.
So it depends on whether f is a member of an unknown specialization. But it isn't:
14.6.2.1 Dependent types [temp.dep.type]
5 A name is a member of an unknown specialization if it is
A qualified-id in which [...].
A qualified-id in which [...].
An id-expression denoting the member in a class member access expression (5.2.5) in which [...].
These cannot apply: f is neither qualified nor part of a class member access expression.
Since the only way f can be dependent is if it is a member of an unknown specialization, and it is not a member of an unknown specialization, f must not be dependent.
As for why compilers nonetheless treat it as dependent, I have no answer. Either some part of my answer here is wrong, the compilers have bugs, or the compilers follow a different version of the C++ standard. Testing with an example that works regardless of whether names are dependent shows a few variations in compiler treatment:
#include <cstdio>
void f(const char *s, ...) { std::printf("%s: non-dependent\n", s); }
struct S1 { };
template <typename T>
struct S2 {
static S1 a;
static S1 b() { return {}; }
template <typename U>
static U c() { return {}; }
static void z() {
f("S1()", S1()); // sanity check: clearly non-dependent
f("T()", T()); // sanity check: clearly dependent
f("a", a); // compiler agreement: non-dependent
f("b()", b()); // compiler disagreement: dependent according to GCC 4.8, non-dependent according to clang
f("c<T>()", c<T>()); // sanity check: clearly dependent
f("c<S1>()", c<S1>()); // compiler agreement: dependent
f("decltype(b())()", decltype(b())()); // compiler agreement: dependent
}
};
void f(const char *s, S1) { std::printf("%s: dependent\n", s); }
// Just to show it's possible to specialize the members
// without specializing the full template.
template <>
S1 S2<S1>::b() { return {}; }
template <>
template <>
S1 S2<S1>::c<S1>() { return {}; }
int main() {
S2<S1>::z();
}
This difference in clang's treatment of b(), decltype(b())(), and c<S1>() is particularly troubling to me. It just doesn't make any sense. They're clearly all equally dependent. I can understand from an implementation point-of-view that care must be taken not to generate code for the member functions just yet because there might be specialisations of S2<S1>::b or S2<S1>::c<S1>, but that applies to all, and has no effect on the return type.

Disambiguator template keyword for a template member of a template: when exactly?

A question regarding template disambiguator was given here:
template disambiguator
and in the answer we can read:
ISO C++03 14.2/4
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.
Now here comes my conrete example that I don't quite understand:
template <class T>
class Base {
public:
template <int v>
static int baseGet() {return v;}
class InnerA {
public:
template <int v>
static int aget() {return v;}
};
class InnerB {
public:
typedef Base BaseType;
typedef BaseType::InnerA OtherType;
template <int v>
static int baseGet() {return BaseType::baseGet<v>();} //(A)
template <int v>
static int aget() {return OtherType::aget<v>();} //(B)
};
};
It obviously fails to compile. You need template in the line (B): OtherType::template aget<v>();.
However, both g++ (4.4.3) and clang++ (2.9) don't complain about the lack of template in the line (A). Why? BaseType depends on the type T, does it not? Is it a small depart from the standard by those compilers, or do I misunderstand something in the standard?
They implement the C++0x specification, where Base is the current instantiation. And C++0x allows to omit template keyword in such a case. Since BaseType is a typedef for Base, when you say BaseType, that names the current instantiation too.
To quote the spec, since you seem to be interested in spec refs
A name is a member of the current instantiation if it is [...]
A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of the current instantiation or a non-dependent base class thereof.
and
A name refers to the current instantiation if it is [...]
in the definition of a [...] nested class of a class template, [...], the injected-class-name (Clause 9) of the class template or nested class
and (the modified 14.2/4 that you quoted)
[...] 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. [...]
Note: In C++03 your code is ill-formed because both BaseType and OtherType are dependent. The spec says:
A type is dependent if it is [...]
a template parameter
a qualified-id with a nested-name-specifier which contains a class-name that names a dependent type
a template-id in which either the template name is a template parameter or any of the template arguments is a dependent type
(note that Base is equivalent to Base<T>, which is the base on which Base and BaseType::InnerA are dependent types).
Note that "explicitly depends" in your quote is a pre-standard term, and was gotten rid of fairly lately (I believe it was at December1996). It basically meant (in this context) a qualified-id in which the qualifier is dependent or a class member access (a->x / a.x) where the a was dependent. After "explicitly depends" was removed from the draft, it was still lurking around at some places, and even C++0x has still references to "explicitly depends" in a note at 14.6.2p2:
the base class name B<T>, the type name T::A, the names B<T>::i and pb->j explicitly depend on the template-parameter.
Because OtherType is a nested dependent name while BaseType is not a nested type to begin with.
You need to use template for nested dependent types.
The keywords here are:
Dependent Type
Nested Type
If a type is both, then you've to use template.
OtherType is both dependent type (it depends on T) as well as nested type
BaseType is only dependent type (it depends on T). Its not a nested type.
BaseType does depend on the type T- but so does InnerB. In effect, from the perspective of any code inside BaseType<T>, it does not depend on T.