Проблема в том, что boost::hana::tuple
не имеет конструктора копирования.
У него есть конструктор , который выглядит как конструктор копирования:
template <typename ...dummy, typename = typename std::enable_if<
detail::fast_and<BOOST_HANA_TT_IS_CONSTRUCTIBLE(Xn, Xn const&, dummy...)...>::value
>::type>
constexpr tuple(tuple const& other)
: tuple(detail::from_index_sequence_t{},
std::make_index_sequence<sizeof...(Xn)>{},
other.storage_)
{ }
Но поскольку это шаблон, он не является конструктором копирования .
Поскольку boost::hana::tuple
не имеет конструктора копирования, один из них объявлен неявно и определено как значение по умолчанию (оно не подавляется, поскольку boost::hana::tuple
не имеет каких-либо конструкторов копирования или перемещения или операторов присваивания, поскольку, как вы уже догадались, они не могут быть шаблонами).
Здесь мы видим реализацию расхождения , продемонстрированную в поведении следующей программы:
struct A {
struct B {} b;
constexpr A() {};
// constexpr A(A const& a) : b{a.b} {} // #1
};
int main() {
auto a = A{};
constexpr int i = (A{a}, 0);
}
g cc принимает, в то время как Clang и MSV C отклоняют, но принимают, если строка #1
не прокомментировано. То есть компиляторы не согласны с тем, допустимо ли использование неявно определенного конструктора копирования не (непосредственно) пустого класса в контексте постоянной оценки.
В соответствии с определением неявно - определенный конструктор копирования , нет никакого способа, которым # 1 отличается от constexpr A(A const&) = default;
, поэтому g cc является правильным. Также обратите внимание, что если мы дадим B пользовательский конструктор копирования constexpr, который Clang и MSV C снова примут, то проблема состоит в том, что эти компиляторы не могут отследить конструктивность копий constexpr рекурсивно пустых неявно копируемых классов. Поданные ошибки для MSV C и Clang ( исправлено для Clang 11).
Обратите внимание, что использование operator[]
является красная сельдь; вопрос заключается в том, позволяют ли компиляторы вызывать getData()
(который копирует-конструирует T
) в контексте постоянной оценки, таком как static_assert
.
Очевидно, что идеальным решением будет Boost. Hana исправить boost::hana::tuple
так, чтобы он имел фактические конструкторы копирования / перемещения и операторы назначения копирования / перемещения. (Это исправит ваш вариант использования, так как код будет вызывать предоставленные пользователем конструкторы копирования, которые допустимы в контексте постоянной оценки.) В качестве обходного пути вы можете рассмотреть взлом getData()
для обнаружения случая без состояния T
:
constexpr T getData() {
if (data == T{})
return T{};
else
return data;
}