仅具有运算符()的结构和普通函数之间的实际区别
Practical difference between a struct with only operator() and a normal function
我见过这样的代码:
struct foo_functor {
template <typename T, typename U>
constexpr auto operator()(T t, U u) const -> decltype(t | u) {
return t | u;
}
};
constexpr foo_functor foo;
据我所知,它与以下内容相同:
template <typename T, typename U>
constexpr auto foo(T t, U u) -> decltype(t | u) {
return t | u;
}
你为什么要做第一个?有什么区别吗?据我从编译器输出中看到,至少在constexpr
的情况下,没有。如果他们不constexpr
,在这种情况下会有什么区别吗?
编辑:请注意,与第一个示例非常相似的代码似乎被用来代替正常功能。 6 种不同的结构,所有结构都只有operator()
个模板,都像示例的最后一行一样实例化。然后,每个都像正常功能一样使用。
有人在评论中建议函数对象可以具有其他状态。虽然这是真的,但我会更具体一点:您可以创建具有不同状态的函数对象的多个副本。如果函数对象是单例,那么这一点就没有意义了;函数也可以具有全局变量形式的状态。
如果你的函数对象被声明为constexpr
,那么它的内部状态都不能是可变的。这使它处于与constexpr
函数相同的位置:调用它可以是一个常量表达式,但前提是它不访问任何非常量表达式全局状态。
在C++17之前的一个重要区别是函数可以inline
,而对象不能。在 C++14 中,如果在标头中定义了函子foo
,则每个翻译单元将有一个副本。如果需要foo
在所有翻译单元中具有相同的地址,则需要将其声明为inline
函数。但在 C++17 中,函数对象也可以是内联的。
但是,即使您只有函数对象的一个实例,并且它没有状态,并且您使用的是 C++17 或更高版本,它与函数之间至少仍然存在一个重要区别:函数可以通过依赖于参数的查找找到,而函数对象不能。这就是为什么 C++20 Ranges 库中的某些"函数"实际上根本不能是函数,而必须是函数对象的原因。这些被非正式地称为尼布洛伊德。
相关文章:
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 填充上编译器生成的复制构造函数之间的不一致
- 为什么不允许成员函数和非成员函数之间的函数重载?
- 如何在"push_*()"和"emplace_*()"函数之间进行选择?
- 仅具有运算符()的结构和普通函数之间的实际区别
- 当两者都调用时,删除和析构函数之间的区别?
- Release() 和析构函数之间的区别?
- 调用 "project" 函数和调用 DLL 函数之间的区别
- C++模板和非模板函数之间的重载解析
- std::shared_ptr 和 std::unique_ptr 构造函数之间的不对称
- C++ 和 Lua 函数之间的交互与 3D 矢量参数
- 在结构函数之间传递文件路径 C++ 编辑:修复LNK2019错误
- 在C++同名的顶级函数之间进行选择
- 在成员函数之间传递const变量为数组的索引
- Helgrind 报告了使用 Singleton 及其构造函数之间可能存在的竞争
- 函数模板和函数之间奇怪的不一致"normal"
- 在c#和c函数之间传递值和指针
- 在C++中调用 malloc() 与"operator new"函数之间的实现差异
- 在函数之间传递相同的数组
- C++编译错误是由于使用 std::move 时运动构造函数与其他非运动构造函数之间的冲突