通过包装器声明朋友 class 模板
Declaring friend class template via wrapper
我看过以下 C++11 之前的代码,用作声明 class 模板友元的技巧(在 C++11 中可以简单地用 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;
}
代码在 g++ (4.9/5.1/6) 上编译正常,但在 clang++ (3.5/3.6/3.7) 下失败并出现错误
error: elaborated type refers to a typedef
friend class Wrapper::type;
上述代码是否符合标准,即是否有效?
不合规。 [class.friend]/3 中 friend
的语法规则是:
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
是这些说明符类型中的 none。它不是 elaborated-type-specifier 因为 Wrapper<T>::type
不是 identifier 或 class-name,显然也不是其他两个之一。您正在寻找的只是:
friend typename Wrapper<T>::type;
[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 ]
代码应该在模板实例化时失败,而在 Clang 中它是正确的。
使用 typename
代替 struct
允许代码在两个编译器中通过。
§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.
我看过以下 C++11 之前的代码,用作声明 class 模板友元的技巧(在 C++11 中可以简单地用 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;
}
代码在 g++ (4.9/5.1/6) 上编译正常,但在 clang++ (3.5/3.6/3.7) 下失败并出现错误
error: elaborated type refers to a typedef
friend class Wrapper::type;
上述代码是否符合标准,即是否有效?
不合规。 [class.friend]/3 中 friend
的语法规则是:
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
是这些说明符类型中的 none。它不是 elaborated-type-specifier 因为 Wrapper<T>::type
不是 identifier 或 class-name,显然也不是其他两个之一。您正在寻找的只是:
friend typename Wrapper<T>::type;
[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 ]
代码应该在模板实例化时失败,而在 Clang 中它是正确的。
使用 typename
代替 struct
允许代码在两个编译器中通过。
§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.