如何将算术运算符传递给模板?

时间:2009-10-26 15:44:50

标签: c++ templates operators

我想以某种方式将这些模板合并为一个:

template <class Result, class T1, class T2>
class StupidAdd
{
public:
    T1 _a; T2 _b;
    StupidAdd(T1 a, T2 b):_a(a),_b(b) {}
    Result operator()() { return _a+_b; }
};

template <class Result, class T1, class T2>
class StupidSub
{
public:
    T1 _a; T2 _b;
    StupidSub(T1 a, T2 b):_a(a),_b(b) {}
    Result operator()() { return _a-_b; }
};

(后面是Mul,Div等的相同代码),其中所有代码都相同, 除了实际的“+”,“ - ”(和“StupidAdd”,“StupidSub”等)。

这些愚蠢的“仿函数”随后被另一个模板使用。 如何在没有预处理器的情况下避免重复? (我进入模板的原因是为了避免预处理器)

也就是说,如何将算术运算符传递给模板?

4 个答案:

答案 0 :(得分:7)

也许您可以使用std::plus<T>std::minus<T>std::multiplies<T>std::divides<T>。但是,只有当两个操作数属于同一类型时,或者如果左侧操作数可以转换为第一个类型,它们才有效。

除了使用预处理器之外,我没有看到任何方法来实现您要做的事情。不想要宏的任何好理由?

如果你想确保返回类型足够大以包含结果,你可以这样做:

#include <functional>
#include <boost/mpl/if_.hpp>

// Metafunction returning the largest type between T and U
// Might already exist in Boost but I can't find it right now...maybe 
// boost::math::tools::promote_args
template <typename T, typename U>
struct largest :
    boost::mpl::if_<
        boost::mpl::bool_<(sizeof(T) > sizeof(U))>,
        T,
        U
    >
{};

template <typename T, typename U, template <typename S> class Op>
struct Foo
{
    typedef typename largest<T, U>::type largeType;

    largeType bar(const T & t, const U & u)
    {
        return Op<largeType>()(t, u); // Applies operator+
    }
};

int main()
{
    Foo<int, double, std::plus> f;
    double d = f.bar(12, 13.0); // takes int and double, returns double
}

在这里,我使用Boost MPL来编写largest元函数,但如果你不能使用Boost(由两种类型和bool参数化的类模板,你可以编写自己的if元函数,专门针对真假)。

要确定表达式的返回类型,您还可以查看boost::result_of,如果我理解正确的话,它等同于C ++ 0x中即将出现的decltype运算符。

答案 1 :(得分:3)

谢谢吕克,这很酷。 我终于以一种更简单的方式做到了:

#include <functional>

template <
    class Result, 
    class T1, 
    class T2,
    template <class ReturnType> class BinaryOp>
class Stupido
{
public:
    T1 _a; T2 _b;
    Stupido(T1 a, T2 b):_a(a),_b(b) {}
    Result operator()() { return BinaryOp<Result>()((Result)_a,(Result)_b); }
};

在实例化Stupido时使用“加号”,“减号”。 “结果”的演员阵容足以满足我的需求(int + double =&gt; double + double =&gt; double)

答案 2 :(得分:3)

我认为OldCoder的解决方案有所改进:

#include <functional>

template <class Result,
          template <class Result> class BinaryOp>
struct Stupido
{
  template <typename T1, typename T2>
  Result operator()(const T1& a, const T2& b) { return BinaryOp<Result>()((Result)a,(Result)b); }
};

这样可以将呼叫设为:

Stupido<int, std::plus > stup;
int result = stup(3.0f, 2.0);

并且相同的函数对象可以与多个操作数一起使用,因此可以将其传递给std::transform调用。

我相信必须有一种方法可以从模板声明中删除一个结果,但我无法找到它。

答案 3 :(得分:0)

我使用C ++ 0x decltype和auto的新定义。您仍然需要定义类,但使用这些类,您可以更好地定义它们。他们仍然需要做大量的工作来定义,但至少使用它们会相当清晰。特别是,您可以使用decltype / auto来推断出正确的返回类型,而不必明确指定它。

最近的编译器有很多版本 - 英特尔C ++,g ++,Comeau,VC ++ 2010的测试版,甚至是Borland / Inprise / Embarcadero /本周新名称的最新版本。