是否存在具有多种访问方法的可变参数模板变体?

Dar*_*ioP 10 c++ templates variant variadic-templates c++11

我达到了50种类型的极限boost::variant.我发现这个漂亮的自包含标题,但它缺乏多访问功能(我实际上需要双重访问).

我试着看一下它,但这种方法似乎非常雄心勃勃,与我缺乏元编程经验相冲突......

如果你可以指出一个预先制作的变体实现或者提供一些建议来扩展我喜欢的那个,那将是非常好的,谢谢!


ToFilipRoséen和upvoters:在这里您可以找到我正在考虑的设计的基本示例.随意添加更多关于此的深入评论.

Man*_*rse 9

编辑:Boost现在支持多访问,C++ 17变体也是如此.


如果您具有带一元visit成员函数的变体类型,则可以将其扩展为n-ary- apply_visitor函数,如下所示:

包括必要的标准库依赖项:

#include <tuple>
#include <type_traits>
#include <utility> //For C++14 `std::integer_sequence`.
                   //If you don't want to use C++14, write your own.
Run Code Online (Sandbox Code Playgroud)

现在是一个辅助函数,用于使新元组与现有元组相同但没有第一个元素:

template<std::size_t ...S, typename Head, typename ...Tail>
std::tuple<Tail...> tuple_tail_impl(
    index_sequence<S...>,
    std::tuple<Head, Tail...> const &in_tuple)
{
    struct In {
        template<std::size_t N>
        using ElementType =
            typename std::tuple_element<N, std::tuple<Head, Tail...>>::type;
    };
    return std::tuple<Tail...>(
        std::forward<In::ElementType<S+1>>(std::get<S+1>(in_tuple))...);
}

template<typename Head, typename ...Tail>
std::tuple<Tail...> tuple_tail(std::tuple<Head, Tail...> const& in_tuple) {
    return tuple_tail_impl(index_sequence_for<Tail...>(), in_tuple);
}
Run Code Online (Sandbox Code Playgroud)

现在,执行该工作的类以及用于创建该类的辅助函数:

template<typename Visitor, typename MatchedValueTuple, typename... TailVariants>
struct NAryVisitorFlattener;

template<typename Visitor, typename MatchedValueTuple, typename... TailVariants>
NAryVisitorFlattener<Visitor, MatchedValueTuple, TailVariants...>
make_NAryVisitorFlattener(
    Visitor &&visitor,
    MatchedValueTuple &&matchedValues,
    std::tuple<TailVariants...> &&tailVariants);
Run Code Online (Sandbox Code Playgroud)

在递归的情况下,NAryVisitorFlattener依次调用apply每个变量上的成员函数并在其中构建结果值MatchedValueTuple.

template<
    typename Visitor,
    typename MatchedValueTuple,
    typename CurrentVariant,
    typename... TailVariants>
struct NAryVisitorFlattener<
    Visitor, MatchedValueTuple, CurrentVariant, TailVariants...>
{
    typedef typename
        std::remove_reference<Visitor>::type::result_type result_type;

    Visitor visitor;
    MatchedValueTuple matchedValues;
    std::tuple<CurrentVariant, TailVariants...> tailVariants;

    template<typename A>
    result_type operator()(A &&a)
    {
      auto flattener = make_NAryVisitorFlattener(
        std::forward<Visitor>(visitor),
        std::tuple_cat(matchedValues, std::forward_as_tuple(std::forward<A>(a))),
        tuple_tail(tailVariants));

      return std::forward<CurrentVariant>(std::get<0>(tailVariants))
                                                             .visit(flattener);
    }
};
Run Code Online (Sandbox Code Playgroud)

在基本情况下,apply已调用每个变体,并使用以下值中的值调用访问者MatchedValueTuple:

template<typename Visitor, typename MatchedValueTuple>
struct NAryVisitorFlattener<Visitor, MatchedValueTuple> {
    typedef typename
        std::remove_reference<Visitor>::type::result_type result_type;

    Visitor visitor;
    MatchedValueTuple matchedValues;
    std::tuple<> tailVariants;

    template<typename A>
    result_type operator()(A &&a) {
        return callFunc(
            std::make_index_sequence<std::tuple_size<MatchedValueTuple>::value>(),
            std::forward<A>(a));
    }

    template<std::size_t N>
    using MatchedValueType =
        typename std::tuple_element<N,MatchedValueTuple>::type;

    template<std::size_t ...S, typename A>
    result_type callFunc(std::index_sequence<S...>, A &&a) {
        return std::forward<Visitor>(visitor)(
            std::forward<MatchedValueType<S>>(matchedValues))...,
            std::forward<A>(a));
    }
};
Run Code Online (Sandbox Code Playgroud)

以前声明的辅助函数的定义:

template<typename Visitor, typename MatchedValueTuple, typename... TailVariants>
NAryVisitorFlattener<Visitor, MatchedValueTuple, TailVariants...>
make_NAryVisitorFlattener(
    Visitor &&visitor,
    MatchedValueTuple &&matchedValues,
    std::tuple<TailVariants...> &&tailVariants)
{
    return {
        std::forward<Visitor>(visitor),
        std::forward<MatchedValueTuple>(matchedValues),
        std::forward<std::tuple<TailVariants...>>(tailVariants)
    };
}
Run Code Online (Sandbox Code Playgroud)

现在,你一直在等待的功能.第一个让球滚动NAryVisitorFlattener:

template<typename Visitor, typename VariantA, typename... Variants>
typename std::remove_reference<Visitor>::type::result_type
apply_visitor(Visitor &&visitor, VariantA &&variantA, Variants &&...variants) {

  auto flattener = make_NAryVisitorFlattener(
    std::forward<Visitor>(visitor),
    std::tuple<>{},
    std::forward_as_tuple(std::forward<Variants>(variants)...));

  return std::forward<VariantA>(variantA).visit(flattener);
}
Run Code Online (Sandbox Code Playgroud)

这一切都是从我的完整C++提供11兼容的变型实施方案采取在这里.