部分专业化的c ++ 17模板推导指南 - 可能吗?

时间:2017-09-30 08:49:13

标签: c++ templates c++17

假设我声明了一个给定arity(参数个数)的函数对象类,它可能介于0和arity参数之间。

这是一个名义上的binary_op的例子,请注意模板推导指南,它允许轻松使用这些功能对象。

#include <tuple>
#include <utility>
#include <iostream>

template<class Pred, class...ArgsR>
struct binary_op
{
    static_assert(sizeof...(ArgsR) <= 2, "binary ops can have max 2 args");
    template<class P, class...As>
    binary_op(P&& p, As&&...as)
    : pred_(std::forward<P>(p))
    , args_r(std::forward<As>(as)...)
    {}

    template<class...ArgsL>
    decltype(auto) operator()(ArgsL&&...args_l) const
    {
        static_assert(sizeof...(ArgsR) + sizeof...(ArgsL) == 2, 
            "binary ops must be executed with 2 args");
        return std::apply(pred_, std::tuple_cat(std::tie(args_l...), args_r));
    }

    Pred pred_;
    std::tuple<ArgsR...> args_r;
};

template<class Pred, class...ArgsR> binary_op(Pred&&, ArgsR&&...) -> binary_op<std::decay_t<Pred>, std::decay_t<ArgsR>...>;


int main()
{
    auto plus_op = [](auto&& x, auto&& y) -> decltype(auto) { return x + y; };
    auto plus = binary_op(plus_op);
    auto plus2 = binary_op(plus_op, 2);
    auto plus2_3 = binary_op(plus_op, 2, 3);

    std::cout << plus(3, 5) << std::endl;
    std::cout << plus2(5) << std::endl;
    std::cout << plus2_3() << std::endl;
}

现在我想概括一下这个想法,并允许规范&#39; arity&#39; (名义参数的数量)作为模板参数。

我第一次尝试为部分特化编写一个演绎指南(未指定Arity模板参数)并不成功,所以我使用了一个未使用的arity<N>构造函数参数:

#include <tuple>
#include <utility>
#include <iostream>

template<std::size_t N>
struct arity : std::integral_constant<std::size_t, N> {};

template<std::size_t Arity, class Pred, class...ArgsR>
struct arity_op
{
    using overall_arity = std::integral_constant<std::size_t, Arity>;

    static_assert(sizeof...(ArgsR) <= overall_arity(), "number of initial args must be less than or equal to arity");

    using function_arity = std::integral_constant<std::size_t, overall_arity() - sizeof...(ArgsR)>;

    template<class P, class...As>
    arity_op(arity<Arity>, P&& p, As&&...as)
    : pred_(std::forward<P>(p))
    , args_r(std::forward<As>(as)...)
    {}

    template<class...ArgsL>
    decltype(auto) operator()(ArgsL&&...args_l) const&
    {
        static_assert(sizeof...(ArgsL) == function_arity(), 
            "arguments to functor must have correct arity");
        return std::apply(pred_, 
                            std::tuple_cat(std::forward_as_tuple(args_l...), 
                            args_r));
    }

    Pred pred_;
    std::tuple<ArgsR...> args_r;
};

template<std::size_t Arity, class Pred, class...ArgsR> arity_op(arity<Arity>, Pred&&, ArgsR&&...) -> arity_op<Arity, std::decay_t<Pred>, std::decay_t<ArgsR>...>;


int main()
{
    auto plus_op = [](auto&& x, auto&& y) -> decltype(auto) { return x + y; };
    auto plus = arity_op(arity<2>(), plus_op);
    static_assert(decltype(plus)::function_arity() == 2, "");

    auto plus2 = arity_op(arity<2>(), plus_op, 2);
    static_assert(decltype(plus2)::function_arity() == 1, "");

    auto plus2_3 = arity_op(arity<2>(), plus_op, 2, 3);
    static_assert(decltype(plus2_3)::function_arity() == 0, "");

    std::cout << plus(3, 5) << std::endl;
    std::cout << plus2(5) << std::endl;
    std::cout << plus2_3() << std::endl;
}

我想我想要的是能够写下:

auto plus = arity_op<2>(plus_op); // arity specified as a template argument

是否可以为这种部分专业化写一个演绎指南?

0 个答案:

没有答案