C ++:使用两个内部类型的运算符作为函数对象

时间:2008-11-16 03:24:13

标签: c++ templates functional-programming

我有一个类似矢量的类,它包含"T"类型的对象数组,我想实现4个算术运算符,它们将对每个项应用操作:

// Constructors and other functions are omitted for brevity.
template<class T, unsigned int D>
class Vector {

public:
    // Add a value to each item: naive implementation.
    void operator += (const T&) {
        for (int i = 0; i < D; ++i) {
            data[i] += value;
        }
    }
    void operator -= (const T&) { ... }
    void operator *= (const T&) { ... }
    void operator /= (const T&) { ... }

private:
    T items[D];
};

因为运算符将包含相同的样板代码(循环遍历每个元素并应用适当的操作),我认为我可以概括它:

template<class T, unsigned int D>
class Vector {

public:
    void operator += (const T& value) { do_for_each(???, value); }
    void operator -= (const T& value) { do_for_each(???, value); }
    void operator *= (const T& value) { do_for_each(???, value); }
    void operator /= (const T& value) { do_for_each(???, value); }

private:
    void
    do_for_each(std::binary_function<void, T, T>& op, T value) {
        std::for_each(data, data + D, std::bind2nd(op, value));
    }

    T data[D];
};

现在,问题是,如何传递一个带有两个内在类型的运算符并将void返回到do_for_each,如上例所示? C ++不允许我对内在类型执行此操作(如果"T::operator+=""T"),"int"将无效。

3 个答案:

答案 0 :(得分:8)

首先,您应该从运算符+ =返回一个引用,因为您以后可以使用它们来实现operator +,operator-等等。我会相应地改变它。

此外,你的do_for_each必须是一个模板,因为它必须知道函数对象的精确类型,因为二进制函数对象不是多态类。对于实际操作,您希望使用std::transform

template<class T, unsigned int D>
class Vector {

public:
    Vector& operator += (const T& value) { 
        do_for_each(std::plus<T>(), value); 
        return *this;
    }

    Vector& operator -= (const T& value) { 
        do_for_each(std::minus<T>(), value); 
        return *this;
    }

    Vector& operator *= (const T& value) { 
        do_for_each(std::multiplies<T>(), value);
        return *this; 
    }

    Vector& operator /= (const T& value) { 
        do_for_each(std::divides<T>(), value); 
        return *this;
    }

private:
    template<typename BinFun>
    void do_for_each(BinFun op, const T& value) {
        std::transform(data, data + D, data, std::bind2nd(op, value));
    }

    T data[D];
};

std::transform只会将每个元素传递给函数对象,并将结果返回给作为第三个参数给出的迭代器。

答案 1 :(得分:2)

你应该真正了解Boost Operators,这是一个仅限标题的库,可以真正简化创建正交和一致算术运算符重载的过程。

具体来说:您可能会发现从boost::operators::integer_arithmatic<T>派生可以为您节省大量的课程重复次数。

答案 2 :(得分:1)

我认为litb是在正确的轨道上并回答了确切的问题 但我认为这是错误的解决方案。

我宁愿不使用do_for_each(),而是直接使用std :: transform():

template<class T, unsigned int D>
class Vector 
{

  public:
    Vector& operator += (const T& value) { 
        std::transform(data, data + D, data, std::bind2nd(std::plus<T>(),value)); 
        return *this;
    }

    Vector& operator -= (const T& value) { 
        std::transform(data, data + D, data, std::bind2nd(std::minus<T>(),value)); 
        return *this;
    }

    Vector& operator *= (const T& value) { 
        std::transform(data, data + D, data, std::bind2nd(std::multiplies<T>(),value));
        return *this; 
    }

    Vector& operator /= (const T& value) { 
        std::transform(data, data + D, data, std::bind2nd(std::divides<T>(),value)); 
        return *this;
    }

  private:
    T data[D];
};