不能在函数内声明运算符。 Clang 错误或规范?

Cannot declare an operator within a function. Clang bug or spec?

C 的一个奇怪的极端情况是函数可以在其他函数中声明,例如

void foo(void)
{
  void bar(void); // Behaves as if this was written above void foo(void)
  bar();
}

这已经进入了 C++,至少对于大多数函数来说是这样。如果所讨论的函数恰好被称为 operator==.

,Clang 似乎无法识别该模式
struct foo
{
  int value;
};

struct bar
{
  foo value;
};

bool wot(const bar &x, const bar &y)
{
  bool eq(const foo &, const foo &);         // Declare function eq
  bool operator==(const foo &, const foo &); // Declare function operator==
  bool func = eq(x.value, y.value);          // This line compiles fine
  bool call = operator==(x.value, y.value);  // Also OK - thanks user657267!
  bool op = x.value == y.value;              // This one doesn't
  return func && call && op;
}

bool test()
{
  bar a;
  bar b;
  return wot(a,b);
}

GCC 和 ICC 编译这个很好。检查对象中的名称重整表明 operator== 已使用正确的类型声明。 Clang(我尝试了 3.8)错误:

error: invalid operands to binary expression
      ('const foo' and 'const foo')
      bool op = x.value == y.value;
                ~~~~~~~ ^  ~~~~~~~

除非将声明移到函数的正上方,在这种情况下 Clang 也很高兴:

bool operator==(const foo &, const foo &);
bool wot(const bar &x, const bar &y)
{
  return x.value == y.value; // fine
}

我无法使用此解决方法,因为引发此问题的 "real world" 案例涉及模板层,这意味着我只知道函数声明中的类型名称 "foo"。

我认为这是 Clang 中的一个错误 - 是否对禁止在函数内声明它们的 operatorX 自由函数进行了特殊处理?

C 确实允许在函数内部声明函数:6.7.5.3 函数声明符§17(C99 的草案 n1256)说(强调我的)

If the declaration occurs outside of any function, the identifiers have file scope and external linkage. If the declaration occurs inside a function, the identifiers of the functions f and fip have block scope and either internal or external linkage (depending on what file scope declarations for these identifiers are visible), and the identifier of the pointer pfi has block scope and no linkage.

C++ 也允许它们。 C++ 14 的 n4296 草案说:

13.2 Declaration matching [over.dcl]
...
2 A locally declared function is not in the same scope as a function in a containing scope. [ Example:
void f(const char*);
void g() {
extern void f(int);
...

(上面的引用只是为了明确证明 C++ 允许在函数内部声明函数)

我什至可以用你的示例这一行来测试它:

bool op2 = operator == (x.value, y.value);

编译正常,没有任何警告,并给出预期结果。

所以我会说这是 Clang 中的一个错误

对于重载运算符,请参阅 [over.match.oper]/(3.2):

[…] for a binary operator @ with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose cv-unqualified version is T2, […] non-member candidates […] are constructed as follows:

The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls (3.4.2) except that all member functions are ignored. However, if no operand has a class type, […]

也就是说,我们有与普通调用中完全相同的名称查找规则,因为x.value是class类型(foo)。这是一个 Clang 错误,所有二元运算符都会出现。归档为 #27027.