【问题标题】:boost::range::combine with repeated argumentboost::range::结合重复参数
【发布时间】:2017-03-17 09:56:09
【问题描述】:

我想将boost::range::combine 用作笛卡尔幂,而不是仅用作乘积。

因此,不要像 boost::range::combine(myRange, myRange, myRange); 这样的表达式,而是写像 myCombine(myRange, 3); 这样的东西。

如何实现?

【问题讨论】:

    标签: c++11 boost variadic-templates boost-range


    【解决方案1】:

    在 C++17 或 C++14 中实现它会更容易和更干净,但是因为你用 标记了它,所以这是一个兼容的实现。这是调用 函数对象 f 的通用方法,其中相同的参数重复 N 次。

    首先,我们需要一种方法来绑定通用函数对象 f 的第一个参数,然后接受任意数量的参数:

    template <typename TF, typename T>
    struct bound
    {
        TF _f;
        T _x;
    
        template <typename TFFwd, typename TFwd>
        bound(TFFwd&& f, TFwd&& x)
            : _f{std::forward<TFFwd>(f)}, _x{std::forward<TFwd>(x)}
        {
        }
    
        template <typename... Ts>
        auto operator()(Ts&&... xs)
            -> decltype(_f(_x, std::forward<Ts>(xs)...))
        {
            return _f(_x, std::forward<Ts>(xs)...);
        }
    };
    
    template <typename TF, typename T>
    auto bind_first(TF&& f, T&& x)
        -> decltype(bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x)))
    {
        return bound<TF&&, T&&>(std::forward<TF>(f), std::forward<T>(x));
    }
    

    然后,我们需要一个递归的 helper 来绑定参数 x 多个 TN 次:

    template <std::size_t TN>
    struct helper
    {
        template <typename TF, typename T>
        auto operator()(TF&& f, T&& x)
            -> decltype(helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x))
        {
            return helper<TN - 1>{}(bind_first(std::forward<TF>(f), x), x);
        }
    };
    
    template <>
    struct helper<0>
    {
        template <typename TF, typename T>
        auto operator()(TF&& f, T&& x)
            -> decltype(f(x))
        {
            return f(x);
        }
    };
    

    最后,我们可以提供一个漂亮的界面:

    template <std::size_t TN, typename TF, typename T>
    auto call_with_same_arg(TF&& f, T&& x)
        -> decltype(helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x)))
    {
        return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
    }
    

    用法:

    int add(int a, int b, int c)
    {
        return a + b + c;   
    }
    
    int main()
    {
        assert(call_with_same_arg<3>(add, 5) == 15);
    }
    

    live wandbox example


    这是同一事物的完整 C++17 实现:

    template <std::size_t TN, typename TF, typename T>
    decltype(auto) call_with_same_arg(TF&& f, T&& x)
    {
        if constexpr(TN == 1)
        {
            return f(x);
        }
        else
        {
            return call_with_same_arg<TN - 1>(
                [&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
        }
    }
    

    live wandbox example


    为了完整起见,C++14 实现:

    template <std::size_t TN>
    struct helper
    {
        template <typename TF, typename T>
        decltype(auto) operator()(TF&& f, T&& x)
        {
            return helper<TN - 1>{}(
                [&](auto&&... xs){ return f(x, std::forward<decltype(xs)>(xs)...); }, x);
        }
    };
    
    template <>
    struct helper<0>
    {
        template <typename TF, typename T>
        decltype(auto) operator()(TF&& f, T&& x)
        {
            return f(x);
        }
    };
    
    template <std::size_t TN, typename TF, typename T>
    decltype(auto) call_with_same_arg(TF&& f, T&& x)
    {
        return helper<TN - 1>{}(std::forward<TF>(f), std::forward<T>(x));
    }
    

    live wandbox example

    【讨论】:

    • 感谢您的回答。如果您有其他 c++ 标准的解决方案,请随时在此处编写。我刚刚写了 c++11,以表明它可能(并且确实是)模板元编程技巧。
    • 哦,好的,你刚刚发布了c++17版本。 c++14 是否有与 c++17 相同的简单解决方案?
    • @YaroslavKishchenko:它有点长,但比 C++11 好。将在几秒钟内发布。
    • @YaroslavKishchenko:完成。你基本上不需要boundbind_first
    • 非常感谢。我会分析你的答案然后批准))
    猜你喜欢
    • 2012-09-06
    • 1970-01-01
    • 2012-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多