【发布时间】:2015-10-02 21:39:53
【问题描述】:
给定
template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
TupleTree<Pack, T1, T2>应该是
Pack<
Pack<int, bool>, Pack<int, double>, Pack<int, int>, Pack<int, char>,
Pack<char, bool>, Pack<char, double>, Pack<char, int>, Pack<char, char>,
Pack<double, bool>, Pack<double, double>, Pack<double, int>, Pack<double, char>
>
这扩展到任意数量的元组。容易理解定义吗?好的,我的程序运行正常:
但现在我想将定义扩展到
`TupleTreeWithRepeats<P, std::index_sequence<Is...>, Tuples...>`
其中Is... 将指示每个元组重复使用的次数,直到移动到下一个元组。请注意<Is...> = <1,1,...,1> 将减少到与TupleTree<P, Tuples...> 相同。我坚持的歧义在于这两个专业:
TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, P<Ts...>, First, Rest...>
TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...>
由于某种原因,P<Ts...> 的存在会导致歧义,因为当我将其替换为单一名称类型时,歧义已被消除。即使我用std::index_sequence<I, Is...> 替换std::index_sequence<Is...>,歧义仍然存在。这是怎么回事?以及如何解决这个问题?下面是代码,和TupleTree的代码差不多:
#include <iostream>
#include <tuple>
#include <type_traits>
template <typename T> struct Identity { using type = T; };
// Merging packs of types.
template <typename...> struct MergePacks;
template <typename Pack>
struct MergePacks<Pack> : Identity<Pack> {};
template <template <typename...> class P, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P<Types1...>, P<Types2...>, Packs...> : MergePacks<P<Types1..., Types2...>, Packs...> {};
// Appending a type to a pack.
template <typename Pack, typename T> struct AppendType;
template <template <typename...> class P, typename... Ts, typename T>
struct AppendType <P<Ts...>, T> {
using type = P<Ts..., T>;
};
// ExpandPackWithTuple takes a pack, and creates N packs that each end with the tuple's elements, N is the size of the tuple.
template <template <typename...> class P, typename Pack, typename Tuple, typename Indices> struct ExpandPackWithTupleHelper;
template <template <typename...> class P, typename Pack, typename Tuple, std::size_t... Is>
struct ExpandPackWithTupleHelper<P, Pack, Tuple, std::index_sequence<Is...>> {
using type = P<typename AppendType<Pack, typename std::tuple_element<Is, Tuple>::type>::type...>;
};
template <template <typename...> class P, typename Pack, typename Tuple>
using ExpandPackWithTuple = typename ExpandPackWithTupleHelper<P, Pack, Tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>>::type;
// TupleTreeWithRepeats.
template <template <typename...> class P, typename NumRepeats, std::size_t LoopNumber, typename OutputPack, typename... Tuples> struct TupleTreeWithRepeatsHelper;
template <template <typename...> class P, std::size_t I, std::size_t... Is, std::size_t LoopNumber, typename... Ts, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, LoopNumber, P<Ts...>, First, Rest...> :
TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, LoopNumber + 1, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, First, Rest...> {};
template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Ts, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...> :
TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 0, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, Rest...> {};
template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename OutputPack>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, OutputPack> {
using type = OutputPack;
};
template <template <typename...> class P, typename NumRepeats, typename... Tuples> struct TupleTreeWithRepeats;
template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Tuples>
struct TupleTreeWithRepeats<P, std::index_sequence<I, Is...>, Tuples...> : TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 0, P<P<>>, Tuples...> {};
// Testing
template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
using T3 = std::tuple<double, int>;
int main() {
std::cout << std::is_same<
TupleTreeWithRepeats<Pack, std::index_sequence<1,1,1>, T1, T2, T3>::type,
Pack<
Pack<int, bool, double>, Pack<int, bool, int>, Pack<int, double, double>, Pack<int, double, int>, Pack<int, int, double>, Pack<int, int, int>, Pack<int, char, double>, Pack<int, char, int>,
Pack<char, bool, double>, Pack<char, bool, int>, Pack<char, double, double>, Pack<char, double, int>, Pack<char, int, double>, Pack<char, int, int>, Pack<char, char, double>, Pack<char, char, int>,
Pack<double, bool, double>, Pack<double, bool, int>, Pack<double, double, double>, Pack<double, double, int>, Pack<double, int, double>, Pack<double, int, int>, Pack<double, char, double>, Pack<double, char, int>
>
>::value << '\n'; // ambiguous
}
【问题讨论】:
-
有趣的是,clang 并不模棱两可:coliru.stacked-crooked.com/a/4272e7d68f252d6e
-
我正在使用 GCC 5.1 进行编译。顺便说一下,我刚刚稍微编辑了我的代码,因为我在第二个专业化中发现了一个逻辑错误。但模糊性仍然是主要问题。但在我微调专业化和测试输出之前,首先需要消除歧义。
-
@MarcoA。我认为编译只是在那个上超时。查看深度较少的输出,clang 似乎在进行一些无限递归。
-
@T.C.我倾向于认为你是对的,尽管我本来希望得到反馈
标签: c++ templates c++11 variadic