Defining a Friend Template Function in a Class

I have no idea why gcc is compiling this code

#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 and msvc don't compile and it seems to me that they are right. Is this a bug in the GCC compiler? The gcc version is 4.8.2.

The question is triggered by my answer in the question: The socket operator in the class does not seem to be involved in overload resolution , there is a quote from the standard answer indicating that such a definition should be in the class-scope, and if the function is not a template - gcc rejects this code , it is right. Thanks for the answers and quotes from the standard, which proves that gcc is right (or not) very much appreciated.

+3


source to share


1 answer


I would argue that GCC is taking this wrong. Quoting C ++ 11, emphasis mine:

Namespace Membership, 7.3.1.2/3

Every name declared in a namespace is a member of that namespace. If a declaration friend

in a non-local class first declares a class or function, the
class or friend's function is a member of the innermost environment of the Namespace. The friend's name was not found by an unqualified lookup (3.4.1) or by a qualified lookup (3.4.3) until a matching declaration is specified in that namespace scope (before or after defining the friendship grant class). If a friend's function is called, its name can be found by name, which takes into account functions from namespaces and classes associated with the function's argument types (3.4.2). ...

Argument-Dependent Search, 3.4.2 / 2:



For each type of argument T

in a function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes. Sets of namespaces and classes are defined entirely by the types of function arguments (and the namespaces of any template template argument). The Typedef names and used declarations used to indicate types do not contribute to this set. Namespace sets and classes are defined as follows:

  • ...
  • If T

    is an enumeration type, its associated namespace is the namespace in which it is defined. If it is a member of a class, the associated class is the member class; else it has no associated class.
  • ...

3.4.2 / 4:

When considering a linked namespace, searches are performed in the same way as searches performed when the linked namespace is used as a classifier (3.4.3.2), except that:

  • ...
  • Any namespace name functions or friend function templates declared in related classes are visible within their respective namespaces, even if they are not visible during normal lookups (11.3).
  • ...

Based on the above, I assume that FooValueT

(type FooValueT::ONE

u FooValueT::TWO

) has ::

both an associated namespace, but no associated classes (since it is an enumeration). Therefore, the friend functions defined in the class template ImplAdd

should not be counted during ADL.

+3


source







All Articles