2

I've seen the following pre-C++11 code, used as a trick to declare class template friends (which in C++11 can simply be done with friend T;)

template <typename T>
struct Wrapper
{
    typedef T type;
};

template <typename T> 
class Foo
{
    friend class Wrapper<T>::type; // effectively makes T a friend
};

struct Test{};

int main()
{
    Foo<Test> foo;
}

The code compiles fine on g++ (4.9/5.1/6), but fails under clang++ (3.5/3.6/3.7) with the error

error: elaborated type refers to a typedef

friend class Wrapper::type;

Is the code above standard compliant, i.e. valid or not?

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • Related: http://stackoverflow.com/questions/21952658/type-dependent-nested-name-specifier-in-elaborated-type-specifier – David G May 21 '15 at 18:33
  • or http://stackoverflow.com/questions/14623338/elaborated-type-refers-to-typedef-error-when-trying-to-befriend-a-typedef – Anton Savin May 21 '15 at 18:48

3 Answers3

1

§7.1.6.3/2:

If the identifier resolves to a typedef-name or the simple-template-id resolves to an alias template specialization, the elaborated-type-specifier is ill-formed.

Columbo
  • 60,038
  • 8
  • 155
  • 203
0

It's not compliant. The grammar rules for friend in [class.friend]/3 are:

A friend declaration that does not declare a function shall have one of the following forms:

friend elaborated-type-specifier ;
friend simple-type-specifier ;
friend typename-specifier ;

class Wrapper<T>::type is none of those specifier types. It's not an elaborated-type-specifier because Wrapper<T>::type isn't an identifier or a class-name, and obviously isn't one of the other two either. What you're looking for is simply:

friend typename Wrapper<T>::type;
Barry
  • 286,269
  • 29
  • 621
  • 977
  • `friend class-key nested-name-specifier identifier ;` is allowed by 7.1.6.3 – Columbo May 21 '15 at 19:03
  • @Columbo So if `Wrapper::type` was some actual type, rather than an alias, you could do `friend class Wrapper::type`? Why allow a type but not an alias? – Barry May 21 '15 at 19:07
  • Yes, that is valid. Not sure about the second part, but I'll look for a DR. – Columbo May 21 '15 at 19:12
0

[dcl.typedef]/p8:

[ Note: A typedef-name that names a class type, or a cv-qualified version thereof, is also a class-name (9.1)

If a typedef-name is used to identify the subject of an elaborated-type-specifier (7.1.6.3), a class definition (Clause 9), a constructor declaration (12.1), or a destructor declaration (12.4), the program is ill-formed. — end note ] [Example:

struct S {
    S();
   ~S();
};

typedef struct S T;
S a = T(); // OK
struct T * p; // error

end example ]

The code should fail at template instantiation time, which it does so correctly in Clang.

Using typename in place of struct allows the code to pass in both compilers.

David G
  • 94,763
  • 41
  • 167
  • 253