【问题标题】:How can I pass an arithmetic operator to a template?如何将算术运算符传递给模板?
【发布时间】:2009-10-26 15:44:49
【问题描述】:

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

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”等)。

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

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

【问题讨论】:

  • 你是想重载这些操作符还是这只是一个例子?
  • 我没有重载算术运算符 - 我只是希望能够在模板中传递它们,例如模板 Result DoWork(A a , B b) { return ArithOp(a,b); ...没有定义愚蠢的东西,如 StupidAdd、StupidSub

标签: c++ templates operators


【解决方案1】:

也许您可以使用std::plus&lt;T&gt;std::minus&lt;T&gt;std::multiplies&lt;T&gt;std::divides&lt;T&gt;。但是,只有当两个操作数的类型相同,或者左边的操作数可以转换为第一个操作数的类型时,这些才会起作用。

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

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

#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,你可以编写自己的if 元函数(由两种类型和一个bool 参数化的类模板,专门用于true 和false) .

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

【讨论】:

  • 我不能 - 我取决于 operator+(int, double) 返回双精度的事实。 std::plus 需要两个 args 的类型相同。
  • 我讨厌“cpp”的基本原因是它让调试变得生不如死——你开始使用宏的那一刻就是你失去在gdb中一步一步执行的能力的那一刻。 .
  • 我只是在编辑以反映这一事实:)。那么,我看不出有任何方法可以做到这一点。除非可以获取内置运算符的地址,我对此表示怀疑。
【解决方案2】:

谢谢 Luc,这太酷了。 我终于以更简单的方式做到了:

#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 => double + double => double)

【讨论】:

    【解决方案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 调用。

    我相信一定有办法从模板声明中删除一个结果,但我找不到它。

    【讨论】:

    • template class BinaryOp> struct Stupido {...};
    【解决方案4】:

    我会使用 C++ 0x decltype 和 auto 的新定义。您仍然需要定义类,但使用这些类,您可以更好地定义它们。它们仍然需要定义同样多的工作,但至少使用它们会相当干净。特别是,您可以使用 decltype/auto 来推断正确的返回类型,而不必显式指定它。

    这些可用于相当数量的最新编译器 - 英特尔 C++、g++、Comeau、VC++ 2010 测试版,甚至是 Borland/Inprise/Embarcadero/本周的新名称的最新迭代。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-16
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-03
      相关资源
      最近更新 更多