为什么C ++中用于算术运算的功能对象被实现为模板?

问题描述

我想知道为什么 c ++ 中的功能对象是作为模板实现的,自 c ++ 14 起,void认类型。

例如:

当由+调用时,该对象实际上执行算术运算-*/operator()

operator()必须是模板,才能与不同类型的参数一起使用,但是为什么必须使用该结构?

编辑

我可以创建一个运算符std::plus<>,该运算符可以与operator()中的其他类型一起使用:

struct Foo{
    int foo;
};

Foo operator+(const Foo& lhs,const Foo& rhs){
    return {2 * lhs.foo + 3 * rhs.foo};
}

std::ostream& operator<<(std::ostream& os,const Foo& f){
    std::cout << f.foo;
    return os;
 }

int main()
{
    auto op = std::plus<>();
    std::cout << op(5,3) << "\n";
    std::cout << op(3.14,2.71) << "\n";
    std::cout << op(Foo(2),Foo(3)) << "\n";
}

这给出了预期的输出。也许是这样,最初指定类型后,您会得到一些更优化的信息吗?

解决方法

这是一种设计选择。如果指定类型,则没有模板operator(),而是整个类都是模板。 operator()就像

constexpr T operator()(const T &lhs,const T &rhs) const 
{
    return lhs + rhs;
}

这与拥有模板operator()有所不同。

如果我们通过std::plus<int>,则它是专门用于int的正函子,

如果我们改为通过std::plus<>而不指定类型,则它将具有模板化的operator()。该函子可以将operator()应用于任何有效类型。

从头顶上限制类型的一些优点:

由于指定了类型,函子可以处理隐式转换而没有任何问题。

您实际上知道函子不会默默地做我们不希望做的事情。只会在T上做加法。

修改

一些行为不同的例子。

#include <iostream>
#include <functional>
#include <string>

struct Foo {};


int main()
{
    auto stringadd = std::plus<std::string>{};
    auto anyadd = std::plus<>{};

    std::cout << stringadd("hey ","you") << '\n';
    //std::cout << anyadd("hey ","you") << '\n'; // error: no match for call to '(std::plus<void>) (const char [5],const char [4])'

    //std::cout << stringadd("hey ",1) << '\n'; // error: no match for call to '(std::plus<std::__cxx11::basic_string<char> >) (const char [5],int)'
    std::cout << anyadd("hey ",1) << '\n';
}