Основные понятия C++20: явное создание частично упорядоченных ограничений для функций-членов
Это работает и выводит «1», потому что ограничения функции частично упорядочены, и побеждает наиболее ограниченная перегрузка:
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (std::same_as<T, int> && !std::same_as<T, char>) {
return 1;
}
};
int main() {
std::cout << B<int>{}.f();
}
Это также работает, потому что явное создание экземпляров не создает экземпляры функций-членов с неудовлетворенными ограничениями:
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (!std::same_as<T, int>) {
return 1;
}
};
template struct B<int>;
Так что же это должно делать?
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (std::same_as<T, int> && !std::same_as<T, char>) {
return 1;
}
};
template struct B<int>;
В настоящее время это приводит к сбою магистрального gcc, потому что он компилирует две функции с одинаковым искажением. Думаю, имеет смысл скомпилировать только вторую функцию, чтобы поведение соответствовало разрешению обычной перегрузки. Что-нибудь в стандарте обрабатывает этот крайний случай?
1 ответ
C++20 признает, что одни и те же эффективные требования могут быть написаны по-разному. Так стандарт определяет два понятия: «эквивалентный» и «функционально эквивалентный».
Истинная «эквивалентность» основана на соблюдении ODR (правило одного определения):
Два выражения, включающие параметры шаблона, считаются эквивалентными , если два определения функций, содержащих выражения, удовлетворяют правилу одного определения, за исключением того, что токены, используемые для именования параметров шаблона, могут различаться, если токен, используемый для именования параметра шаблона в одном выражении, заменен другим токеном, который называет тот же параметр шаблона в другом выражении.
Это еще не все, но здесь это не проблема.
«Функциональная эквивалентность» заключается в том, всегда ли два выражения имеют одинаковые результаты:
Два потенциально вычисляемых выражения, включающие неэквивалентные параметры шаблона, функционально эквивалентны, если для любого заданного набора аргументов шаблона вычисление выражения приводит к одному и тому же значению.
Обратите внимание, что по определению функциональная эквивалентность исключает эквивалентность ODR.
Два ваших выражения ограничения в версиях 1 и 3 не эквивалентны ODR, но функционально эквивалентны. И поведение этого кода будет отличаться от его поведения, если бы они были эквивалентны ODR. Таким образом, этот отрывок срабатывает :
Если валидность или смысл программы зависят от того, эквивалентны ли две конструкции, и они функционально эквивалентны, но не эквивалентны, программа плохо сформирована, диагностика не требуется.
Таким образом, все компиляторы одинаково правы, потому что ваш код неверен. Очевидно, что компилятор не должен сразу давать сбой (и это должно быть представлено как ошибка), но «плохой формат, не требующий диагностики» часто влечет за собой непредвиденные последствия.