【问题标题】:Daisy chain variadic templated classes菊花链可变参数模板类
【发布时间】:2015-07-09 14:11:02
【问题描述】:

我有一个类模板管道:

template <typename A, typename B> class Pipeline;

我想创建一个可变参数函数模板,接受任意数量的任意Pipelines,并且我想以一种棘手的方式限制它们。非可变参数代码如下所示:

Pipeline<A, C> compose(Pipeline<A, B> p1, Pipeline<B, C> p2);
Pipeline<A, D> compose(Pipeline<A, B> p1, Pipeline<B, C> p2, Pipeline<C, D> p3);
// ...and so on

现在有可能以可变的方式端到端地约束它们吗?

// I would like to write something like:
Pipeline<Args[0], Args[len(Args)-1]> compose(Pipeline<Args[i], Args[i+1]> ps...);

【问题讨论】:

  • 你能显示为 Pipeline 的定义吗?
  • 当然可以。可能有点冗长。
  • template&lt;typename A, typename B&gt; struct Pipeline { B run(A); } 应该可以解决问题。它基本上是一个冗长的函数'A -> B',我想编写函数组合。
  • 从一个从列表中取出一对的元函数开始:Pair&lt;2, T1, T2, T3, T4&gt; == T2, T3,等等。最终你想要像f(Pair&lt;Idx, Args&gt;...)这样的东西
  • Pipeline 本身是可变参数模板,还是只有两种类型?从您的问题的措辞中不清楚。

标签: c++ templates variadic-templates variadic-functions


【解决方案1】:

我假设您的 Pipeline 看起来像:

template <typename A, typename B>
struct Pipeline {
    using first = A;
    using second = B;
};

首先,让我们为什么是有效的链链接创建一个类型特征:

template <typename P1, typename P2>
struct is_valid_link : std::false_type { };

template <typename A, typename B, typename C>
struct is_valid_link<Pipeline<A,B>, Pipeline<B,C>> : std::true_type { };

接下来,让我们借用@Columbo 的bool_pack 技巧来验证那一堆bools 都是true

template <bool...> struct bool_pack;

template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;

当然我们还需要索引序列技巧:

template <typename... Pipelines,
          typename R = decltype(detail::daisy_chain(
                                    std::make_index_sequence<sizeof...(Pipelines)-1>(),
                                    std::declval<Pipelines>()...))
         >
R compose(Pipelines... pipelines)
{
    return {};
}

大部分工作都在这里进行检查:

namespace detail {
    template <size_t... Is,
              typename... Pipelines,
              typename T = std::tuple<Pipelines...>,
              typename R = std::enable_if_t<
                          // ensure that all our pairwise pipelines are valid links
                                all_true<
                                    is_valid_link<std::tuple_element_t<Is,T>,
                                                  std::tuple_element_t<Is+1,T>>::value...
                                    >::value,
                           // pick out the first and last types
                                Pipeline<typename std::tuple_element_t<0, T>::first,
                                         typename std::tuple_element_t<sizeof...(Pipelines)-1, T>::second>
                            >>
    R daisy_chain(std::index_sequence<Is...>, Pipelines... pipelines);
}

我们可以这样做:

int main() {
    Pipeline<int, double> p = compose(Pipeline<int, char>{}, Pipeline<char, double>{});
}

这样写的好处是你仍然有 SFINAE - 如果你想要的话。这样:

auto invalid = compose(Pipeline<int, char>{}, Pipeline<float, double>{});

将触发重载解析失败:

main.cpp:46:31: error: no matching function for call to 'compose'
    Pipeline<int, double> p = compose(Pipeline<int, char>{}, Pipeline<float, double>{});
                              ^~~~~~~
main.cpp:40:3: note: candidate template ignored: substitution failure [with Pipelines = <Pipeline<int, char>, Pipeline<float, double>>]: no matching function for call to 'daisy_chain'
R compose(Pipelines... pipelines)
  ^
1 error generated.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-01
    • 2021-10-01
    相关资源
    最近更新 更多