Использование typename в C ++ 20 требует / concept?

Обратите внимание на следующую программу на C ++ 20:

#include <iostream>

template<typename T>
struct A {
    using X = typename T::X;
};

template<typename T>
constexpr bool WorksWithA = requires { typename A<T>; };

struct GoodArg {
    using X = int;
};

struct BadArg {
};

int main() {
    std::cout << WorksWithA<GoodArg> << std::endl;
    std::cout << WorksWithA<BadArg> << std::endl;
}

Это плохо сформировано? А если нет, то каким должен быть результат?

Я ожидал, что результат будет 1 0, но наблюдаю clang 1 1. Кто прав и почему?

$ clang++ --version
clang version 10.0.0-4ubuntu1 
$ clang++ test.cc -std=c++20
$ ./a.out 
1
1

person Andrew Tomazos    schedule 15.02.2021    source источник
comment
WorksWithA всегда будет истинным, потому что A<T> не ограничен.   -  person bolov    schedule 15.02.2021
comment
если вы перешли на requires { typename T::X; } то работает   -  person PiotrNycz    schedule 15.02.2021
comment
@PiotrNycz: Конечно, но почему эта программа не выводит 1 0? См. Этот связанный вопрос: stackoverflow.com/q/66208977/1131467   -  person Andrew Tomazos    schedule 15.02.2021
comment
@bolov: Значит, ответ на этот вопрос: stackoverflow.com/q/66208977/1131467 неверен?   -  person Andrew Tomazos    schedule 15.02.2021
comment
Да, это не так, но мне нужно проверить стандарт, чтобы убедиться.   -  person bolov    schedule 15.02.2021


Ответы (1)


Концепция здесь просто именует тип A<BadArg>, он ничего не делает, чтобы инициировать его создание. Ничто здесь не приводит к созданию экземпляра A<BadArg>::X, который был бы неправильно сформирован.

Если бы это было так, то вы все равно не получили бы false, вы получили бы плохо сформированную программу. Например, сделали ли вы:

template<typename T>
constexpr bool WorksWithA = requires { A<T>{}; };

Затем WorksWithA<BadArg> вызовет создание экземпляра A<BadArg>, который попытается найти BadArg::X, что теперь является ошибкой вне непосредственного контекста подстановки. Не false, ошибка компиляции.

Если вам нужен результат false, вам придется ограничить шаблон A существующим типом:

template <typename T>
    requires requires { typename T::X; }
struct A {
    using X = typename T::X;
};

И теперь обе формулировки (ваша исходная и моя заменяющая) дали бы false вместо WorksWithA<BadArg>.

person Barry    schedule 15.02.2021
comment
Спасибо, Барри, не могли бы вы взглянуть на этот вопрос: stackoverflow.com/q/66208977/1131467 Итак, ответ на это вопрос нет возможности это сделать? - person Andrew Tomazos; 15.02.2021
comment
@AndrewTomazos Кажется, тот же вопрос, что и этот? - person Barry; 15.02.2021
comment
A<T>{} также потребует построения по умолчанию. - person Jarod42; 15.02.2021
comment
@ Jarod42 Да? Это был просто пример, демонстрирующий, как обеспечить создание экземпляра. - person Barry; 15.02.2021
comment
В основном, чтобы подчеркнуть OP, что оба требования были близки, но не эквивалентны. И A<T>{} - не лучшее требование. - person Jarod42; 15.02.2021
comment
Другой вопрос, можем ли мы обнаружить жесткую ошибку ... мягко ... - person Jarod42; 15.02.2021