通过包装器声明朋友类模板

时间:2015-05-21 18:31:45

标签: c++ templates language-lawyer friend

我见过以下的C ++ 11之前的代码,用作声明类模板朋友的技巧(在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)下失败并出现错误

  

错误:详细说明类型是指typedef

     

朋友类Wrapper :: type;

上述代码是否符合标准,即是否有效?

3 个答案:

答案 0 :(得分:1)

§7.1.6.3/ 2:

  

如果标识符解析为 typedef-name 或    simple-template-id 解析为别名模板专精, elaborated-type-specifier 格式错误

答案 1 :(得分:0)

它不合规。 [class.friend] / 3中friend的语法规则是:

  

未声明函数的朋友声明应具有以下形式之一:

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

class Wrapper<T>::type不是那些说明符类型。它不是详细说明类型说明符,因为Wrapper<T>::type不是标识符类名,显然也不是其他两个中的一个。您正在寻找的只是:

friend typename Wrapper<T>::type;

答案 2 :(得分:0)

[dcl.typedef] / P8:

  

[注意:命名类类型或其cv限定版本的 typedef-name 也是类名(9.1)

     

如果 typedef-name 用于标识详细类型说明符 (7.1.6.3)的主题,则为类定义   (第9条),构造函数声明(12.1)或析构函数声明(12.4),程序格式错误。    - 结束记录] [示例

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

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

- 结束示例]

代码应该在模板实例化时失败,它在Clang中正确执行。

使用typename代替struct,代码可以在两个编译器中传递。