Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a local class dependent if declared within a function template?

Current C++ compilers (latest gcc, clang) require the typename keyword in the example below:

template<class T>
struct A
{
};

template<class T>
void f(T)
{
    struct C
    {
    };
    typedef typename A<C>::Type Type; // typename required
}

If typename is omitted gcc (4.9, 5.0) reports the error:

need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope

This example is otherwise well-formed according to my reading of the C++11 standard.

This behaviour seems to be covered by the following wording:

[temp.dep.type]/8

A type is dependent if it is

  • a template parameter,

  • a member of an unknown specialization,

  • a nested class or enumeration that is a 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 constructed from any dependent type or whose size is specified by a constant expression that 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

  • denoted by decltype(expression), where expression is type-dependent.

However, according to [class.local] the class C is a local class rather than a nested class. If so, why should A<C> be treated as dependent?

EDIT

For bonus points, if the example is modified by adding a member enum to C as follows:

template<typename T>
struct A
{
    typedef T Type;
};

template<class T>
void f(T)
{
    struct C
    {
        enum { value = T::value };
    };
    typedef typename A<C>::Type Type; // typename required
}

Should A<C> now be treated as dependent?

like image 876
willj Avatar asked Sep 30 '22 02:09

willj


1 Answers

According to my understanding (and the current wording of the standard), C in your example is not dependent. Neither is A<C>::Type, so the typename is not required.

There is a fundamental difference between nested classes of class templates and local classes in function templates: The latter cannot be specialized, thus any reference to a local class inside a function template is uniform. That is, in every specialization of f, C refers to the class C that is defined in this function template f. That is not the case with class templates as you can indeed explicitly specialize members on their own (as covered in [temp.expl.spec] /(1.6)):

template <typename T>
class A { class C{}; };

template <>
class A<int>::C { int i; };

However:

A type is dependent if it is

  • a compound type constructed from any dependent type,

So if the definition was done as in dyp's example, C would be dependent as it is constructed from T.
There are unclarities in the standards wording that are being discussed in the comment section, e.g. about definitions of member functions that depend on T and how that transposes to the classes dependency.

like image 97
5 revs Avatar answered Oct 05 '22 07:10

5 revs