朋友模板函数在类定义

时间:2014-12-11 08:30:39

标签: c++ c++11 gcc language-lawyer

我不知道,为什么gcc会编译这段代码

#include <type_traits>

template<class Type, class ValueT>
class ImplAdd
{
   template<typename T>
   friend typename std::enable_if<std::is_same<T, ValueT>::value, Type>::type 
   operator+(T, T)
   {
      return Type{};
   }
};

enum class FooValueT { ONE, ZERO };

class Foo : ImplAdd<Foo, FooValueT>
{
public:
   Foo() {}
   Foo(FooValueT) {}
};

struct A {};

int main()
{
   Foo f = FooValueT::ONE + FooValueT::ZERO;
}
clang和msvc没有编译,在我看来,他们是对的。它是GCC编译器中的错误吗? gcc的版本是4.8.2。

问题是由我的问题答案引起的:In-class friend operator doesn't seem to participate in overload resolution,答案中有标准引用,指出这样的定义应该在类范围内,如果函数不是模板 - gcc拒绝此代码,这是对的。感谢您的答案,以及标准的引用,证明gcc是对(或不对)非常感激。

1 个答案:

答案 0 :(得分:3)

我会说GCC接受这个错误。引用C ++ 11,强调我的:

命名空间成员资格,7.3.1.2 / 3

  

首先在名称空间中声明的每个名称都是该名称空间的成员。 如果非本地的friend声明   class首先声明一个类或函数友元类或函数是最内层封闭的成员   命名空间。 非限定查找(3.4.1)或限定查找(3.4.3)找不到朋友的名称,直到在该命名空间范围内提供匹配声明(在类定义之前或之后)   给予友谊)。 如果调用了友元函数,则可以通过考虑的名称查找找到其名称   来自名称空间的函数和与函数参数类型相关的类(3.4.2)。 ...

依赖于参数的查找,3.4.2 / 2:

  

对于函数调用中的每个参数类型T,都有一组零个或多个关联的命名空间和一个   要考虑的零个或多个关联类的集合。确定名称空间和类的集合   完全由函数参数的类型(以及任何模板模板参数的命名空间)组成。   用于指定类型的Typedef名称和 using-declarations 对此集合没有贡献。套   命名空间和类的确定方式如下:

     
      
  • ...
  •   
  • 如果T是枚举类型,则其关联的命名空间是定义它的命名空间。如果是   类成员,其关联类是成员的类; 其他没有关联的课程。
  •   
  • ...
  •   

3.4.2 / 4:

  

在考虑关联的命名空间时,查找与执行时的查找相同   关联命名空间用作限定符(3.4.3.2),但以下情况除外:

     
      
  • ...
  •   
  • 任何命名空间范围的朋友函数或朋友函数模板在关联类中声明   即使它们在普通查找期间不可见(11.3),也可以在各自的命名空间中可见。
  •   
  • ...
  •   

基于以上所述,我推断FooValueTFooValueT::ONEFooValueT::TWO的类型)具有::作为关联的命名空间,但没有关联的类(因为这是一个枚举)。因此,在ADL期间不应考虑在类模板ImplAdd中定义的友元函数。