gpt4 book ai didi

c++ - 是否有具有多访问方法的可变参数模板变体?

转载 作者:可可西里 更新时间:2023-11-01 15:53:28 25 4
gpt4 key购买 nike

我在 boost::variant 中达到了 50 种类型的限制.我找到了 this nice self-contained header但它缺少多次访问功能(我实际上需要双重访问)。

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

如果您能指出一个预煮的变体实现或提供一些建议来扩展上面我喜欢的那个,那就太好了,谢谢!


致 Filip Roséen 和投票者:here您会找到我正在考虑的设计的基本示例。请随时添加更多关于此的深入评论。

最佳答案

编辑:Boost 现在支持 multi-visitation , C++17 variant 也是如此.


如果你有一个带有一元 visit 的变体类型成员函数,这可以扩展为 n 元- 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.

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

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);
}

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

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);

在递归情况下,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);
}
};

在基本情况下,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));
}
};

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

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)
};
}

现在,您一直在等待的功能。让球滚动第一个 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);
}

这全部取 self 可用的完整 C++11 兼容变体实现 here .

关于c++ - 是否有具有多访问方法的可变参数模板变体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24042788/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com