在询问this question about parameter pack folding into pairs之后,我注意到我需要保留以前折叠类型的完整类型作为左对类型。
例如:
Fold<char, int, long, double> f;
必须评估为
std::tuple<
std::pair<char
, int>,
std::pair<std::pair<char, int> /* <-- the previous resulting type */
, long>,
std::pair<std::pair<std::pair<char, int>, long> /* the previous type again */
, double>
> f;
我之所以需要这个,是因为必须折叠的类型&#34;可以是占位符类型。占位符&#34;真实&#34;只有当左侧具有完全展开类型以及未展开类型时,才能知道类型。 最左边的类型从不包含占位符。
让我用一个简单的例子来说明这一点:
struct CopyTypeFromPreviousArgumentTag { };
template<typename T = CopyTypeFromPreviousArgumentTag>
struct Foo;
template<typename T...>
struct Bar {
/* Here fold will not use std::pair, but a resolver type that takes both A and B and gives back the resolved B */
Fold<T...> expanded;
};
现在Bar
可以像这样使用:
Bar< Foo<int>
, Foo<>
, Foo<>
, Foo<double>
, Foo<>
> f;
,内部类型decltype(f::expanded)
将为:
std::tuple< Foo<int>
, Foo<int>
, Foo<int>
, Foo<double>
, Foo<double>
>;
编辑: Bar
类实际上不限于它可能包含的任何类类型。它可以是几种类型的混合物。因此,请将Foo
类视为某种类型Foo
的占位符,其中存在解析器类型特征,并且先前已解析类型:ResolveType<PreviouslyResolvedType, CurrentType>::Type
将正确地提供已解析的类型。因此std::pair
成语。
我试图通过建立链接问题的答案来实现递归,但无法使其起作用。
namespace Detail {
template<typename, typename...>
struct Fold;
template
< size_t... Indices
, typename... Types
> struct Fold<std::index_sequence<Indices...>, Types...> {
using Tuple = std::tuple<Types...>;
using Type = std::tuple<std::pair /* use std::pair just to match the first example */
//< std::tuple_element_t<Indices, Tuple>
< typename Fold
< std::tuple_element_t<Indices, Tuple>
, std::make_index_sequence<Indices>
, Types...>::Type; /* Tuple can't be expanded :( */
, std::tuple_element_t<Indices + 1, Tuple>
>::Type...>;
};
} /* namespace Detail */
template<typename... Types>
using Fold = typename Detail::Fold<std::make_index_sequence<sizeof...(Types) - 1>, Types...>::Type;
答案 0 :(得分:4)
链接的问题是一种非常复杂的方式。如果它是一个运行时问题,它显然可以用一次通过算法解决,元编程也没有什么不同。
struct copy_prev {};
template<typename T = copy_prev>
struct Foo {};
template<typename... Ts, typename T>
auto operator+(std::tuple<Ts...>, Foo<T>)
-> std::tuple<Ts..., Foo<T>>;
template<typename... Ts>
auto operator+(std::tuple<Ts...> t, Foo<copy_prev>)
-> std::tuple<Ts..., select_last_t<Ts...>>;
template<typename... Ts>
using fold_t = decltype((std::tuple<>{} + ... + std::declval<Ts>()));
将select_last_t
实施为
template<typename T>
struct tag
{
using type = T;
};
template<typename... Ts>
struct select_last
{
using type = typename decltype((tag<Ts>{}, ...))::type;
};
template<typename... Ts>
using select_last_t = typename select_last<Ts...>::type;
答案 1 :(得分:2)
不确定你想要什么...但是如果你的Bar
结构只接受Foo
类型......那就是:if可以写成如下
template <typename ...>
struct Bar;
template <typename ...Ts>
struct Bar<Foo<Ts>...>
{ /* something */ };
并在Bar
中想要一个类型,以便从
Bar<Foo<int>, Foo<>, Foo<>, Foo<double>, Foo<>>
你想要内部类型
std::tuple<Foo<int>, Foo<int>, Foo<int>, Foo<double>, Foo<double>>
Foo
的未表达(默认)参数被最后表达的参数替换...我没有看到优雅的解决方案。
我能想象的最好的是如下所示的类型助手的开发(为简洁起见,我已将ctfpat
重命名为CopyTypeFromPreviousArgumentTag
}
template <typename...>
struct fooFolder;
// error case: the first type of Bar is ctfpat (non impemented;
// generate compile time error)
template <typename ... Ts>
struct fooFolder<std::tuple<>, ctfpat, ctfpat, Ts...>;
template <typename ... Tps, typename Tprev, typename T0, typename ... Ts>
struct fooFolder<std::tuple<Tps...>, Tprev, T0, Ts...>
: fooFolder<std::tuple<Tps..., Foo<T0>>, T0, Ts...>
{ };
template <typename ... Tps, typename Tprev, typename ... Ts>
struct fooFolder<std::tuple<Tps...>, Tprev, ctfpat, Ts...>
: fooFolder<std::tuple<Tps..., Foo<Tprev>>, Tprev, Ts...>
{ };
template <typename Tpl, typename Tprev>
struct fooFolder<Tpl, Tprev>
{ using type = Tpl; };
和Bar
成为
template <typename ...>
struct Bar;
template <typename ...Ts>
struct Bar<Foo<Ts>...>
{
using foldedType = typename fooFolder<std::tuple<>, ctfpat, Ts...>::type;
foldedType expanded;
};
以下是完整的编译示例
#include <tuple>
#include <type_traits>
struct ctfpat // copy type from previous argument tag
{ };
template <typename T = ctfpat>
struct Foo
{ };
template <typename ...>
struct fooFolder;
// error case: the first type of Bar is ctfpat (non impemented;
// generate compile time error)
template <typename ... Ts>
struct fooFolder<std::tuple<>, ctfpat, ctfpat, Ts...>;
template <typename ... Tps, typename Tprev, typename T0, typename ... Ts>
struct fooFolder<std::tuple<Tps...>, Tprev, T0, Ts...>
: fooFolder<std::tuple<Tps..., Foo<T0>>, T0, Ts...>
{ };
template <typename ... Tps, typename Tprev, typename ... Ts>
struct fooFolder<std::tuple<Tps...>, Tprev, ctfpat, Ts...>
: fooFolder<std::tuple<Tps..., Foo<Tprev>>, Tprev, Ts...>
{ };
template <typename Tpl, typename Tprev>
struct fooFolder<Tpl, Tprev>
{ using type = Tpl; };
template <typename ...>
struct Bar;
template <typename ... Ts>
struct Bar<Foo<Ts>...>
{
using foldedType = typename fooFolder<std::tuple<>, ctfpat, Ts...>::type;
foldedType expanded;
};
int main()
{
using t1 = typename Bar<Foo<>, Foo<int>, Foo<>, Foo<double>,
Foo<>>::foldedType;
using t2 = std::tuple<Foo<int>, Foo<int>, Foo<int>, Foo<double>,
Foo<double>>;
static_assert( std::is_same<t1, t2>{}, "!" );
}