Различие C ++ 17 и C ++ 20 в функции друга шаблона с унарными и бинарными операторами - PullRequest
8 голосов
/ 06 мая 2020

У меня есть следующий MWE на C ++ 20 с clang++ -std=c++2a, в котором я определил унарный оператор - класса и friend -ed двоичный оператор -:

template<typename T>
class vec;

template<typename T>
vec<T> operator-(const vec<T>&, const vec<T>&);

template<typename T>
class vec {
public:
    vec() {}
    vec operator-() const { return vec(); }
    friend vec operator-<>(const vec&, const vec&);
};

template<typename T>
vec<T> operator-(const vec<T>& lhs, const vec<T>& rhs) { return vec<T>(); }

int main()
{
    vec<int> v;
    return 0;
}

Однако это приводит к следующей ошибке в C ++ 17:

main.cpp:12:16: error: friends can only be classes or functions
    friend vec operator-<>(const vec&, const vec&);
               ^
main.cpp:12:25: error: expected ';' at end of declaration list
    friend vec operator-<>(const vec&, const vec&);
                        ^
                        ;

с Apple clang version 11.0.3 (clang-1103.0.32.59).

Ошибка исчезает, когда я удаляю унарный оператор в классе или когда Я использую C ++ 20 через -std=c++2a.

Что вызывает эту проблему в C ++ 17 и как C ++ 20 решает эту проблему? Любая помощь будет принята с благодарностью!

1 Ответ

1 голос
/ 08 мая 2020

Это связано с тем, как поиск имени происходит внутри контекста класса. Ищите имена внутри декларатора друзей, ищите, как и в любых деклараторах членов. Соответствующие правила поиска, которые применяются здесь:

In во всех случаях, перечисленных в [basi c .lookup.unqual], в областях выполняется поиск объявления в порядке, указанном в каждой из соответствующих категорий; Поиск имени заканчивается, как только для имени найдено объявление. Если объявление не найдено, программа имеет неправильный формат.

Имя, используемое в определении класса X вне контекста полного класса ([class.mem]) X, должно быть объявлено одним из следующих способов:

  • до его использования в классе X или быть членом базового класса X ([class.member.lookup]), или
  • [...]
  • , если X является членом пространства имен N, или является вложенным классом класса, который является членом N, или является локальным классом или вложенным классом в локальном классе функции, которая является членом N, до определения класса X в пространстве имен N или в одном из охватывающих пространств имен N.

Это означает, что:

  1. имена сначала ищутся в области класса для имен членов ;

  2. , если предыдущий поиск завершился неудачно, имя ищется в охватывающей области пространства имен.

Когда компилятор находит имя operator- в объявлении друга он выполняет поиск имени в контексте класса (неполный). Он находит унарный оператор минус и останавливается на нем.

После этого компилятор применяет следующее правило, чтобы определить, может ли имя operator - быть именем шаблона C ++ 17 / [temp.name] / 3

После поиска по имени обнаруживает, что имя является именем шаблона или что идентификатор-функции-оператора или идентификатор-литерала-оператора относится к набору перегруженных функций любого члена из которых является шаблоном функции, если за ним следует <, то <всегда используется как разделитель списка аргументов-шаблонов и никогда не используется как оператор «меньше». [...] </p>

Поиск не нашел ни одного шаблона, поэтому в объявлении друга operator - не предполагается называть шаблон. Компилятор жалуется именно на токен <, следующий за этим именем, которого там не должно быть.

Новое правило C ++ 20 делает компилятор более склонным интерпретировать, что имя относится к шаблону, C ++ 20 standard / [temp.names] / 2 :

Считается, что имя относится к шаблону, если поиск имени обнаруживает имя шаблона или набор перегрузки который содержит шаблон функции. Имя также считается относящимся к шаблону, если это неквалифицированный идентификатор, за которым следует <и <strong>поиск имени либо находит одну или несколько функций, либо ничего не находит .

Имя поиск в области видимости класса vec найдите имя функции, за которым следует символ <, так что это имя относится к шаблону.

...