4
votes

Compiling with Clang 3.0 -std=c++98, the following code is accepted:

template<int>
struct I
{
    typedef int Type;
};

template<class>
struct S
{
    static int f(int);
    //static int f(int*);

    // implicitly instantiates I<sizeof(int)>
    typedef I<sizeof(f(0))>::Type Type; 
};

S<int>::Type s;

Uncommenting the overload of 'f' causes Clang to report an error "missing 'typename' prior to dependent type name". G++ 4.8 reports the same error with or without the overload. msvc10 does not give any errors with or without the overload.

Where does the standard say whether or not 'f' is dependent and 'typename' is required? If 'typename' is not required, where does the standard say whether or not overload resolution should be performed in this scenario?

EDIT:

To clarify: the reason I mention overload resolution is that it may be necessary to perform overload resolution to determine the value of the constant-expression 'sizeof(f(0))'. If (as I assume) overload resolution is not performed when determining whether an expression is type-dependent, the value of the constant-expression 'sizeof(f(0))' is impossible to determine (at parse time) when a dependent overload of 'f' exists: e.g.

template<int>
struct I
{
    typedef int Type;
};

template<class T>
struct S
{
    static T f(int);

    typedef typename I<sizeof(f(0))>::Type Type; 
};

S<int>::Type t;

Compiling with Clang 3.0 -std=c++98, this produces no errors. This seems correct to me, because the standard deems an expression to be type-dependent if it is an id-expression naming an object declared with a dependent type.

3
I fail to see dependent situation with or without the overload, so would bet on overlook in Clang. MSVC traditionally accepted code with missing typename so not necessarily conclusive though. Too bad we can no longer use Cameau online.Balog Pal
In C++2003, [temp.dep.expr]/4 "Expressions of the following forms are never type-dependent [...] sizeof unary-expression"; [temp.dep.constexpr]/2 "Expressions of the following form are value-dependent if the unary-expression is type-dependent or the type-id is dependent [...] sizeof unary-expression"dyp
I just saw that and added it to my comment :) Nevertheless, f(0) is not a type-dependent nor a value-dependent expression AFAIKdyp
Interestingly, g++4.8 has the same problem with typedef I<sizeof(&f)>::Type Type; iff f is a static function (but not if it's a static data member).dyp
Which version of clang do you use? My clang++3.2 compiles this w/o complaints.dyp

3 Answers

2
votes

Dependent names are defined in 14.6.2. gcc complains about I<sizeof(f(0))> being dependent, let's figure that. 14.6.2.1 last bullet:

a 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

so sizeof(f(0)) must be value-dependent. 14.6.2.3p2:

Expressions of the following form are value-dependent if the unary-expression is type-dependent ... sizeof unary-expression

so we're dependent if f(0) considered dependent. (Little experimenting shows gcc treats member any function dependent and free functions not dependent.) 14.6.2.2:

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

And I don't see either type dependent subexpressions or anything relevant in the exception list.

2
votes

The paragraph of the C++98 standard that covers this scenario is found in [temp.dep.expr]

An id-expression is type-dependent if it contains:

  • an identifier that was declared with a dependent type,

This wording is somewhat vague about identifiers that are overloaded and potentially declared with more than one type, as reported in DR 541 : http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html

This was resolved (in a more recent draft) by changing the paragraph to read:

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,

When considering the following code:

template<class T>
struct S
{
    static int f(int);
    static int f(int*);

    static T g(int*);
    static int g(int);

    static const int x = sizeof(f(0));
    static const int y = sizeof(g(0));
};

My interpretation is that the identifier f in the expression f(0) is not dependent, while the identifier g in the expression g(0) is dependent.

When determining if a function-call expression is dependent - though overload resolution is not performed - all overloads of the function are considered.

0
votes

f is a member of S, which is a template, so any use of f within S is dependent on the template parameters of S.

14.6.2.3 [temp.dep.constexpr] paragraph 2:

An id-expression is value-dependent if:

...

— it names a static member function that is a dependent member of the current instantiation

This applies to 'f' here, which is a dependent member of the current instantiation. 14.6.2.1 [temp.dep.types] paragraph 4:

...

A name is a dependent member of the current instantiation if it is a member of the current instantiation that, when looked up, refers to at least one member of a class that is the current instantiation.

Consequently sizeof(f(0)) is dependent, I<sizeof(f(0))> is dependent, and I<sizeof(f(0))>::Type needs typename to identify it as a type and not a data member.

gcc is therefore right to complain.

MSVC does late lookup with templates, so doesn't complain. This is a bug, but I don't think they ever intend to fix it.

Clang appears to have a bug here.