Невозможно объявить оператор внутри функции. Ошибка Clang или spec?
Один из странных угловых случаев C состоит в том, что функции могут быть объявлены в рамках других функций, например.
void foo(void)
{
void bar(void); // Behaves as if this was written above void foo(void)
bar();
}
Это перенесено на С++, по крайней мере для большинства функций. 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 составляют этот штраф. Проверка имени в объекте предполагает, что оператор == был объявлен с правильными типами. 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
}
Я не могу использовать это обходное решение, так как случай "реального мира", вызвавший этот вопрос, включает в себя слои шаблонов, то есть я знаю только имя типа "foo" в объявлении функции.
Я считаю, что это ошибка в Clang - есть ли специальная обработка бесплатных функций operatorX, которая запрещает объявление их внутри функции?
Ответы
Ответ 1
Для перегруженных операторов см. [over.match.oper]/(3.2):
[...] для двоичного оператора @
с левым операндом типа, cv-неквалифицированная версия которого T1
и правый операнд типа, cv-unqualified версия T2
, [...] non-member кандидаты [...] построены следующим образом:
Набор кандидатов, не являющихся членами, является результатом неквалифицированного поиск [email protected]
в контексте выражения в соответствии с обычные правила поиска имен в неквалифицированных вызовах функций (3.4.2) за исключением того, что все функции-члены игнорируются. Однако, если никакой операнд имеет тип класса, [...]
То есть, мы имеем точные правила поиска одинакового имени, как в обычных вызовах, потому что x.value
имеет тип класса (foo
). Это ошибка Clang, и она встречается со всеми бинарными операторами. Подано как # 27027.
Ответ 2
Верно, что C позволяет объявлять функции внутри функций: 6.7.5.3 Объявление функций §17 (проект n1256 для C99) говорит (подчеркивайте мое)
Если декларация происходит вне любой функции, идентификаторы имеют размер файла и внешнюю привязку. Если объявление происходит внутри функции, идентификаторы функций f и fip имеют масштаб блока и либо внутренняя или внешняя связь (в зависимости от того, какие видимые области видимости для этих идентификаторов видны) и идентификатор указателя pfi имеет область видимости блока и отсутствие привязки.
С++ также позволяет им. В проекте n4296 для С++ 14 говорится:
13.2 Согласование соответствия [over.dcl]
...
2 Локально объявленная функция не входит в ту же область действия, что и функция в содержащей области. [Пример:
void f (const char *);
void g() {
extern void f (int);
...
(приведенная цитата только здесь, чтобы иметь явное доказательство того, что С++ допускает объявления функций внутри функции)
Я мог бы даже проверить, что с вашим примером эта строка:
bool op2 = operator == (x.value, y.value);
компилируется без единого предупреждения и дает ожидаемые результаты.
Итак, я бы сказал, что это ошибка в Clang