【问题标题】:Template Alias Difficulty模板别名难度
【发布时间】:2015-09-10 20:59:42
【问题描述】:

我有以下几点:

template <typename T, std::size_t End, std::size_t Count, template <typename...> class P,
typename... Accumulated, typename... Added, template <typename, T...> class Z, T... Is, 
std::size_t... Js>
struct Generate<T, End, Count, P<Accumulated...>, P<Added...>, Z<T, Is...>, Js...> :
    Generate<T, End, Count + 1, typename Merge<P, P<Accumulated...>,
        typename AppendEachToPack<T, P, Added, Is...>::type...>::type,
        typename Merge<P, typename AppendEachToPack<T, P, Added, Is...>::type...>::type,
        Z<T, Is...>, Js...> {};

因为typename AppendEachToPack&lt;T, P, Added, Is...&gt;::type... 被计算了两次,所以我想将上面的内容重写为

template <typename T, std::size_t End, std::size_t Count, template <typename...> class P,
typename... Accumulated, typename... Added, template <typename, T...> class Z, T... Is,
std::size_t... Js>
struct Generate<T, End, Count, P<Accumulated...>, P<Added...>, Z<T, Is...>, Js...> :
    GenerateAlias<T, End, Count + 1, P, P<Accumulated...>, Z<T, Is...>,
    typename AppendEachToPack<T, P, Added, Is...>::type..., Js...> {};

在哪里

template <typename T, std::size_t End, std::size_t Count, template <typename...> class P,
typename Output, typename Sequence, typename... Expanded, std::size_t... Js>
using GenerateAlias = Generate<T, End, Count, typename Merge<P, Output, Expanded...>::type,
typename Merge<P, Expanded...>::type, Sequence, Js...>;

但不接受两包声明typename... Expanded, std::size_t... Js。那么如何实现我想要实现的目标呢?

如果你需要,这里是AppendToEachPackMerge的定义:

// Appending an element to a pack.
template <typename T, T t, typename> struct Append;

template <typename T, T t, template <T...> class Z, T... Is>  
struct Append<T, t, Z<Is...>> {  
    using type = Z<Is..., t>;
};

// Appending many elements to a pack one at a time.
template <typename T, template <typename...> class P, typename Pack, T... Is>
struct AppendEachToPack {
    using type = P<typename Append<T, Is, Pack>::type...>;
};

// Merging multiple packs of types into a single pack of types.
template <template <typename...> class P, typename... Packs> struct Merge;

template <template <typename...> class P, typename Pack>
struct Merge<P, Pack> {
    using type = Pack;
};

template <template <typename...> class P, typename... Ts, typename... Us>
struct Merge<P, P<Ts...>, P<Us...>> {
    using type = P<Ts..., Us...>;
};

template <template <typename...> class P, typename Pack1, typename Pack2, typename... Packs>
struct Merge<P, Pack1, Pack2, Packs...> {
    using type = typename Merge<P, Pack1, typename Merge<P, Pack2, Packs...>::type>::type;
};

【问题讨论】:

  • 单独使用别名模板是不可能的。如果您需要传递多个包,则需要一个支架,然后使用部分专业化或函数模板 + decltype 提取。而且我认为这种对“typename AppendEachToPack&lt;T, P, Added, Is...&gt;::type... 被计算两次”的担忧在任何情况下都是错误的,因为记忆化。 Generate 究竟应该做什么?
  • 例如,Create&lt;int, A, Pack, 3,2, 2,3&gt; 将生成A&lt;Is...&gt;Pack,其中前两个分量将为 0,1 或 2,接下来的三个分量将为 0 或1.我已经完全解决了,只是想完成一些优化。也许Expanded...Js...可以被两个包包裹,那么编译器会接受语法吗?
  • 让我看看我是否理解正确:您的示例生成的包有 3*3*2*2*2 = 72 个成员,每个成员的形式为 A&lt;x,y,z,w,u&gt;,其中 @ 987654339@ 和 y 来自 {0, 1, 2} 和​​ zwu 来自 {0, 1}?
  • 差不多。但这不是问题。我已经解决了。我只想学习如何避免重复计算。如果你愿意,我可以在链接中发布我的完整解决方案,这样你就可以看到最初的目标是什么。这是链接,因此您可以运行它并查看输出:ideone.com/EK7H5y
  • 嗯,为什么你的输出中有 0 0 这样的东西?至于“重复计算”,编译器会记住它已经实例化的模板特化,所以这通常不是问题。

标签: c++ templates c++11 alias variadic


【解决方案1】:

感谢 T.C. 的提示,这是一种解决方案(经测试可以正常工作):

// Helper struct to forward the pack wrapping the problem pack.
template <template <typename...> class P, typename PackOfPacks, typename... OtherPacks>
struct MergeMany;

template <template <typename...> class P, typename... Packs, typename... OtherPacks>
struct MergeMany<P, P<Packs...>, OtherPacks...> : Merge<P, Packs..., OtherPacks...> {};

// Now the desired GenerateAlias.
template <typename T, std::size_t End, std::size_t Count, template <typename...> class P,
    typename Output, typename Sequence, typename Expanded, std::size_t... Js>
using GenerateAlias = Generate<T, End, Count, typename MergeMany<P, Expanded, Output>::type,
    typename MergeMany<P, Expanded>::type, Sequence, Js...>;

// And now using GenerateAlias, so typename AppendEachToPack<T, P, Added, Is...>::type... is computed only once.
template <typename T, std::size_t End, std::size_t Count, template <typename...> class P, typename... Accumulated,
typename... Added, template <typename, T...> class Z, T... Is, std::size_t... Js>
struct Generate<T, End, Count, P<Accumulated...>, P<Added...>, Z<T, Is...>, Js...> :
    GenerateAlias<T, End, Count + 1, P, P<Accumulated...>, Z<T, Is...>,
    P<typename AppendEachToPack<T, P, Added, Is...>::type...>, Js...> {};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2021-12-18
    相关资源
    最近更新 更多