cageman
cageman

Reputation: 333

Function pointer to global operator compiles on VC++ while clang gives an error

I am trying to get the following code to compile on clang, but it fails with the following error:

error: no member named 'operator<' in the global namespace

I tried compiling the visual studio code with /Za to switch to standard conformance, but it still seems to accept it. Enlighten me please.

struct A
{
  int m_test;
  A(int test)
    : m_test(test)
  {

  }

  friend bool operator<(A left, A right);
};

int main()
{
  typedef bool(*TCompare)(A,A);
  TCompare compare = &::operator<;

  compare(9,7);
}

VC++ output: https://godbolt.org/g/LAz56n

Clang output: https://godbolt.org/g/zC2InO

Upvotes: 1

Views: 111

Answers (2)

songyuanyao
songyuanyao

Reputation: 172984

Clang is correct. For your sample code, the name operator< introduced by friend declarations does become the member of the global namespace, but it's not visible to name lookup. It can only be found by ADL, but ADL only applies to function-call expressions, while &::operator< is not.

Names introduced by friend declarations within a non-local class X become members of the innermost enclosing namespace of X, but they do not become visible to lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.

To fix it you have to add a matching declaration at global namespace scope. e.g.

struct A
{
  int m_test;
  A(int test)
    : m_test(test)
  {

  }

  friend bool operator<(A left, A right);
};

// add a matching declaration at namespace scope
bool operator<(A left, A right);

int main()
{
  typedef bool(*TCompare)(A,A);
  TCompare compare = &::operator<;

  compare(9,7);
}

bool operator<(A left, A right) { 
    ... 
}

Upvotes: 5

n. m. could be an AI
n. m. could be an AI

Reputation: 120031

It's a VC++ bug. The code is invalid.

A friend declaration doesn't introduce the declared name to the global namespace. You still need to declare it outside of the class.

Upvotes: 5

Related Questions