Это ошибка в вашей стандартной библиотеке. Предположительно, вы используете libstc ++ (стандартная библиотека GNU C ++), так как это то, что Godbolt показывает, как портит. Если вы компилируете с помощью libc ++ (стандартная библиотека C ++ Clang / LLVM), это работает как положено. Согласно странице cppreference std::vector<Types...>::operator=(T&& t)
, она
Определяет альтернативный тип T_j
, который будет выбран по разрешению перегрузки для выражения F(std::forward<T>(t))
, если бы было перегрузка мнимой функции F(T_i)
для каждого T_i
из типов ... в области действия одновременно, за исключением того, что:
Перегрузка F(T_i)
рассматривается только в том случае, если объявление T_i x[] = { std::forward<T>(t) };
действителен для некоторой изобретенной переменной x
;
Если T_i
(возможно, cv-квалифицирован) bool
, F(T_i)
рассматривается только если std:remove_cvref_t<T>
также bool
.
Последний пункт есть для этой самой ситуации. Поскольку многие вещи могут быть преобразованы в bool
, но мы обычно не предполагаем это преобразование, этот пункт приводит к тому, что выбираются последовательности преобразования, которые обычно не выбираются (char const*
в bool
является стандартным преобразованием, но для std::string
«определяется пользователем», что обычно считается «хуже»). Ваш код должен установить value
в альтернативу std::string
, но реализация вашей библиотеки std::variant
не работает. Возможно, билет на выпуск уже открыт, но если его нет, это является основанием для его открытия. Если вы застряли в своей библиотеке, явное пометить литерал как std::string
должно работать:
literal.value = std::string("Hello World");
Для вопроса элегантности используйте сокращенный шаблон лямбда.
std::ostream &operator<<(std::ostream &os, Literal const &literal)
{
std::visit([](auto v) { std::cout << v; }, literal.value);
// or
std::visit([](auto const &v) {
// gets template param vvvvvvvvvvvvvvvvvvvvvvvvv w/o being able to name it
if constexpr(std::is_same_v<std::decay_t<decltype(v)>, std::nullptr_t>) {
std::cout << "null";
} else std::cout << v;
}, literal.value);
// only difference is nullptr_t => "nullptr" vs "null"
return std::cout;
}
Кроме того, ваше объявление friend
не соответствует определению. На самом деле, он не должен быть friend
ed в любом случае, так как ему не нужен доступ к private
членам.
// declaration in header, outside of any class, as a free function
std::ostream &operator<<(std::ostream&, Literal const&);
// was missing const ^^^^^