Where does the C++98 standard specify when a call to a static member is dependent within a template?

十年热恋 提交于 2019-12-22 08:38:55

问题


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.


回答1:


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:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/16887608/where-does-the-c98-standard-specify-when-a-call-to-a-static-member-is-dependen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!