问题描述
我想知道为什么 c ++ 中的功能对象是作为模板实现的,自 c ++ 14 起,void
是默认类型。
例如:
- https://en.cppreference.com/w/cpp/utility/functional/plus
- https://en.cppreference.com/w/cpp/utility/functional/minus
当由+
调用时,该对象实际上执行算术运算-
,*
,/
,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';
}