Почему std::get‹T›, где T — результат неудачного вызова функции constexpr?

Мой вопрос о том, как на самом деле работает этот код:

std::variant<int, std::string> is;
constexpr int i = 0;
std::cout << std::get<i>(is);

И теперь, если я напишу следующий код, он не работает:

std::variant<int, std::string> is;
std::cout << std::get<is.index()>(is);

В документации https://en.cppreference.com/w/cpp/utility/variant/index я обнаружил, что возвращаемый тип индекса — constexpr. Может кто-то помочь мне с этим?

Обновлять

Теперь, используя std::string_view вместо std::string, который также может быть constexpr, и сделав is также constexpr. Оно работает. Спасибо


person Emanuel Clur    schedule 31.10.2019    source источник
comment
Но «есть» не является constexpr, поэтому is.index() не является постоянным выражением.   -  person Igor R.    schedule 01.11.2019
comment
constexpr не является частью (возвратного) типа. Это спецификатор объявления функции или переменной.   -  person walnut    schedule 01.11.2019
comment
Я хочу сделать что-то вроде внедрения boost:: variant в том, что один 'is' может быть автоматически приведен к типу, необходимому без его разворачивания с помощью std:: get   -  person Emanuel Clur    schedule 01.11.2019
comment
@Вы говорите конкретно о примере кода здесь, содержащий строку std::cout << v << std::endl;? Это работает, потому что boost перегружает operator<< для варианта, а не из-за какого-то магического приведения в зависимости от сохраненного типа.   -  person walnut    schedule 01.11.2019
comment
Вы говорите, что теперь это работает с string_view, но это может быть правдой только в том случае, если вы сделали is также constexpr, и в этом случае is станет неизменяемым. С изменяемым is он не будет работать и с string_view.   -  person walnut    schedule 01.11.2019
comment
О, это имеет смысл, ха-ха. Вот почему я не могу найти boost::variant::operator T().   -  person Emanuel Clur    schedule 01.11.2019
comment
Технически стандарт не указывает, когда index() требуется для возврата константного выражения. Теоретически разработчик библиотеки может, скажем, написать index() таким образом, чтобы это было константное выражение только тогда, когда вариант имеет тип 1, а в противном случае - нет. Это было бы глупо, но стандарт, кажется, позволяет это. Таким образом, вы никогда не можете рассчитывать на то, что index() можно будет использовать в качестве аргумента шаблона.   -  person Brian Bi    schedule 01.11.2019


Ответы (2)


Метод constexpr может возвращать значение constexpr, если он вызывается из значения constexpr.

Итак, вы должны определить is как constexpr

 constexpr std::variant<int, std::string> is;

К сожалению, std::variant нельзя объявить constexpr, если if не является буквальным типом, поэтому, когда один из его типов, например std::string, не является литералом.

Но работает, например

 constexpr std::variant<int, long> is;
person max66    schedule 31.10.2019

Значения параметров шаблона должны быть известны во время компиляции.

std::variant<int, std::string> is;
constexpr int i = 0;
std::cout << std::get<i>(is);

Это работает, потому что значение i объявлено с constexpr и, следовательно, известно во время компиляции, поэтому вы фактически вызываете std::get<0>(is).

std::variant<int, std::string> is;
std::cout << std::get<is.index()>(is);

Это не удается, потому что is не объявлено с constexpr и, следовательно, значение, которое возвращает is.index(), не может быть известно до времени выполнения, поэтому его нельзя использовать в параметре шаблона.

person Remy Lebeau    schedule 31.10.2019