Pregunta

I attempted to get friend name injection to work with the following snippet:

struct foo
{
  friend foo f() { return {}; }
};

int main()
{
  auto x = f();
  return 0;
}

This fails to compile:

test.cc:8:10: error: use of undeclared identifier 'f'
  auto x = f();
           ^
1 error generated.

I have to declare f in the outer namespace for the error to vanish.

The standard has an explanation in paragraph 3 of §7.3.1.2:

If a friend declaration in a non-local class first declares a class, function, class template or function template97 the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). — end note ]

My question: why do we need an extra declaration of f at namespace scope for this to compile? Does it have to do with ADL? Is there a (hacky) way around this requirement?

¿Fue útil?

Solución

You can force ADL:

struct foo {
  friend foo f(foo *) { return {}; }
};

int main()
{
  auto x = f((foo *) 0);
  return 0;
}

Compiles with g++ 4.9.0 and clang++ 3.4. Of course, might not be practical.

ADDENDUM: Thanks to Richard Hodges, here is another possible workaround, but it might be a g++ 4.9.0 bug. There are differences between clang++ and g++. I'll try to look into what the standard says, if I have time. If the OP wants to post this as a new question asking about which compiler is wrong, please do.

struct foo {
  friend foo f1() { return {}; }
  friend foo f2(foo *) { return {}; }
  template<typename T = void>
  friend foo f3() { return {}; }
};

int main()
{
  auto x1 = f1(); // Error, f1() not visible.
  auto x2 = f2((foo *) 0); // Force ADL.
  auto x3 = f3<void>(); // Use template, okay with g++, fails with clang++.
  auto x4 = f3(); // Use template with default param, okay with g++, fails with clang++.
  return 0;
}

Otros consejos

friend works on a declaration, not a definition.

struct foo
{
  friend foo f();
};

foo f() { return {}; }

int main()
{
  auto x = f();
  return 0;
}

compiles

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top