C ++ std :: plus作为模板参数

时间:2017-04-01 14:39:45

标签: c++ templates

我想写一个binary indexed array

的课程

使用两个非类型的默认模板参数opidentity

需要检查op(identity,identity) == identity

的约束

我的问题是

  1. 我不知道如何指定op,我目前的解决方案无法编译‘class std::function<T(T, T)>’ is not a valid type for a template non-type parameter
  2. 如何检查op(identity,identity) == identity ,目前我无法验证,因为第1步失败,可能是static_assert
  3. 所以目前我使用下面的解决方法,但后来我无法指定op,例如std::multiplies<int>。 谁能告诉我如何实现目标?

    #include <vector>
    #include <functional>
    
    // template <typename T = int, std::function<T(T,T)> op = std::plus<T>(), const T identity = T()>
    template <typename T = int, const T identity = T()>     // currently workaround
    class BIT { // binary indexed array
        const std::function<T(T,T)> op = std::plus<T>();    // currently workaround
    public:
        BIT(std::vector<T> value) : value(value), prefixSum(value.size() + 1, identity) {
            for (size_t i = 1; i < prefixSum.size(); ++i) {
                incrementNodeByValue(i, value[i-1]);
            }
            // print(prefixSum,"prefixSum");
        }
        T getSum(size_t i) {
            auto sum = identity;
            while (i) {
                sum = op(sum, prefixSum(i));
                i = firstSmallerAncestor(i);
            }
            return sum;
        }
        void incrementNodeByValue(size_t i, T x) {
            while (i < prefixSum.size()) {
                prefixSum[i] = op(prefixSum[i], x);
                i = firstLargerAncestor(i);
            }
        }
    private:
        inline size_t firstLargerAncestor(size_t node) { return node + (node & -node); }
        inline size_t firstSmallerAncestor(size_t node) { return node & (node - 1); }
        std::vector<T> value;
        std::vector<T> prefixSum;
    };
    
    int main() {
        auto vec = std::vector<int> {5,1,15,11,52,28,0};
        auto bit = BIT<>(vec);
    }
    

1 个答案:

答案 0 :(得分:3)

在这里使用std::function是一种浪费,似乎是您混淆的根源。

请注意,模板只能在类型名称和整数类型的值(charintlong等)上进行参数化。在这里,您尝试参数化std::function实例化的值,该实例化不是整数类型。也就是说,在这种情况下,您实际上不需要对值进行参数化。

因为构造函数不接受初始化op成员变量的参数也不能通过接口访问,所以我认为可以安全地假设运算符在编译时是已知的,保证是不可变的,并且默认可构造。

因此,我将op成员声明为名为operation的参数类型。

#include <functional>
#include <vector>

template< typename T = int,
          typename operation = std::plus<T>, 
          const T identity = T() >
class BIT { 
    const operation op = operation();

    static_assert( operation()(identity, identity) == identity );

    std::vector<T> value;
    std::vector<T> prefixSum;

    inline size_t firstLargerAncestor(size_t node) { return node + (node & -node); }
    inline size_t firstSmallerAncestor(size_t node) { return node & (node - 1); }

 public:
    BIT(std::vector<T> value) : 
        value(value), 
        prefixSum(value.size() + 1, identity) {
        for (size_t i = 1; i < prefixSum.size(); ++i) {
            incrementNodeByValue(i, value[i-1]);
        }
    }

    T getSum(size_t i) {
        auto sum = identity;
        while (i) {
            sum = op(sum, prefixSum(i));
            i = firstSmallerAncestor(i);
        }
        return sum;
    }
    void incrementNodeByValue(size_t i, T x) {
        while (i < prefixSum.size()) {
            prefixSum[i] = op(prefixSum[i], x);
            i = firstLargerAncestor(i);
        }
    }
};

live example

作为一个注释,您可能希望在其他位置定义identity模板以在操作和值类型上进行参数化,以在此处默认第三个参数。在实例化过程中,似乎你几乎总是定义所有三个参数。