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

Why functional objects in C++ for arithmetic operations are implemented as templates?

我想知道,为什么 c++ 中的函数对象被实现为模板化的,并且 void 作为默认类型,因为 c++14.

例如:

当被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(),而是整个 class 是一个模板。 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';
}