Когда требуется заключать выражение в скобки? (игра слов случайно) - PullRequest
3 голосов
/ 06 мая 2020

Это дает ошибку:

template <class T, T A, T B>
    requires A > B             // <-- error
class X{};

error: это выражение необходимо заключать в круглые скобки в требовании

requires A < B

         ~~^~~

         (    )

Почти все операторы выдают эту ошибку (requires A > B, requires A == B, requires A & B, requires !A)

Однако && и ||, похоже, работают:

template <class T, T A, T B>
    requires A && B             // <-- ok
class X{};

Яички с g cc trunk и clang trunk (май 2020 г.) на Godbolt. Оба компилятора дают одинаковые результаты.

Ответы [ 2 ]

3 голосов
/ 06 мая 2020

Требует, чтобы в предложениях использовалась специальная грамматика выражений, чтобы избежать некоторых патологических двусмысленностей синтаксического анализа . Как отмечено в cppreference , допустимыми формами являются

  • a первичное выражение
  • последовательность первичных выражений, соединенных с оператором &&
  • последовательность вышеупомянутых выражений, объединенная с оператором ||
1 голос
/ 06 мая 2020

Да, && и || здесь рассматриваются как особые, потому что ограничения учитывают конъюнкции и дизъюнкции.

§ 13.5.1 Ограничения [temp.constr.constr]

  1. Ограничение - это последовательность логических операций и операндов, определяющая требования к аргументам шаблона. Операнды логической операции - это ограничения. Есть три разных вида ограничений:

    (1.1) - союзы (13.5.1.1), (1.2) - дизъюнкции (13.5.1.1), и (1.3) - ограничения atomi c (13.5.1.2).

Они должны быть, чтобы определить частичное упорядочение по ограничениям.

13.5.4 Частичное упорядочение по ограничениям [temp .constr.order]

[Примечание: [...] Этот частичный порядок используется для определения

  • (2.1) наилучшего жизнеспособного кандидата для нешаблонных функций (12.4.3),
  • (2.2) адрес нешаблонной функции (12.5),
  • (2.3) сопоставление аргументов шаблона шаблона (13.4.3),
  • (2.4) частичное упорядочение специализаций шаблонов классов (13.7.5.2) и
  • (2.5) частичное упорядочение шаблонов функций (13.7.6.2).

- конец примечания]

Что заставляет этот код работать:

template <class It>
concept bidirectional_iterator = requires /*...*/;

template <class It>
concept randomaccess_iterator = bidirectional_iterator<It> && requires /*...*/;

template <bidirectional_iterator It>
void sort(It begin, It end);            // #1

template <randomaccess_iterator It>
void sort(It begin, It end);            // #2
std::list<int> l{};
sort(l.begin(), l.end()); // #A  -> calls #1

std::vector<int> v{};
sort(v.begin(), v.end()); // #B  -> calls #2

Но для вызова #B, даже если оба sort являются жизнеспособными, поскольку оба ограничения (randomaccess_iterator и bidirectional_iterator удовлетворены) sort #2 (тот, у которого randomaccess_iterator) выбран правильно, потому что он более ограничен , чем sort #1 (тот, у которого bidirectional_iterator), потому что randomaccess_iterator включает в себя bidirectional_iterator:

См. Как с концепциями выбирается лучший шаблон ограниченной функции?

...