C++:是否可以编写一个将不同类型的元素附加到变体数组的函数?

标签 c++ c++17 template-meta-programming variant

我正在尝试编写一个函数,例如:

std::array<std::variant<int, std::string_view>, 4>

和一个double d ,并返回:

std::array<std::variant<int, std::string_view, double>, 5>

d附加到数组的末尾,但到目前为止,我在我的实现中遇到了一些非常奇怪的行为。

现在,我有一个 Variant_Monoid (使用二元运算 concatenate )处理扩展 std::variant类型,这似乎工作正常:

struct Variant_Monoid {
    using zero = std::monostate;

    template <typename T, typename... Args>
    struct [[maybe_unused]] concatenate;

    template <typename... Args0, typename... Args1>
    struct concatenate<std::variant<Args0...>, std::variant<Args1...>> {
        using type = std::variant<Args0..., Args1...>;
    };

    // Convenience method to concatenate types without having to wrap them into a variant first.
    template<typename... Args0, typename... Args1>
    struct concatenate<std::variant<Args0...>, Args1...> {
        using type = std::variant<Args0..., Args1...>;
    };
};

然后我有了这个,我的想法是遍历现有数组,尝试将类型从旧变体扩展到新变体,然后附加新元素:

template<size_t N, typename T, typename S>
constexpr std::array<typename Variant_Monoid::concatenate<T, S>::type, N + 1> append_element_with_type(const std::array<T, N> &a, const S &s) {
    return append_element_with_type_aux(a, s, std::make_index_sequence<N>{});
}

委派给这个功能:

template<size_t N, typename T, typename S, size_t... Indices>
constexpr std::array<typename Variant_Monoid::concatenate<T, S>::type, N + 1>
append_element_with_type_aux(const std::array<T, N> &a,
                             const S &s, std::index_sequence<Indices...>) noexcept {
    return {{std::visit([](auto &&t) { return t; }, a[Indices])..., s}};
}

不过,这个函数的行为无处不在。在某些情况下(通常是一系列调用中的第一个调用),它似乎工作正常。例如:

constexpr std::array<std::variant<Variant_Monoid::zero>, 0> s0{};
constexpr std::array<std::variant<Variant_Monoid::zero, int>, 1> s1 = append_element_with_type(s0, 1);

但是,如果我接下来尝试这个,编译器不仅会提示表达式不是 constexpr , 但它完全无法通过一连串无法破译的 STL 消息进行编译:

auto s2 = append_element_with_type(s1, 3.14159);

同样,这似乎没有问题:

constexpr std::array<std::variant<std::string_view>, 3> to_extend = {{"Hello", "there", "world"}};
constexpr std::array<std::variant<std::string_view, int>, 4> extended = append_element_with_type(to_extend, 5);

然后,这再次失败并出现类似的编译错误,并再次声称表达式不是 constexpr :

constexpr std::array<std::variant<std::string_view, int, double>, 5> prepended = append_element_with_type(extended, 3.14);

如有任何建议/帮助,我们将不胜感激。我对模板元编程还很陌生,只是尝试了解更多信息。

最佳答案

对访问者的调用必须为所有可能的参数产生相同的类型和值类别。明确指定您的 lambda 的返回类型为新变体,即 typename Variant_Monoid::concatenate<T, S>::type .

关于C++:是否可以编写一个将不同类型的元素附加到变体数组的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52415279/

相关文章:

c++ - 如何正确编写尾随返回类型?

c++ - 什么时候应该使用直接初始化,什么时候应该使用复制初始化?

c++ - 使用递归C++打印出模式

c++ - bool 内存高效链表

c++ - 一次性定义结构并创建相关数据项列表?

c++ - 当我定义 UNICODE 和/或 _UNICODE 时,非 unicode API 函数会发生什么情况?

c++ - 是否可以在以下代码中避免对复制/移动构造函数的需要?

C++ regex_search 在 C 样式数组上进行匹配

c++ - Vector在C++中的实现

c++ - 什么是类型字符串(模板元编程),它有什么作用?