仅具有operator()的结构与正常函数之间的实际区别 [英] Practical difference between a struct with only operator() and a normal function

查看:86
本文介绍了仅具有operator()的结构与正常函数之间的实际区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过这样的代码:

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;

据我所知,它与以下内容相同:

As far as I can tell, it's the same as the following:

template <typename T, typename U>
constexpr auto foo(T t, U u) -> decltype(t | u) {
  return t | u;
}

为什么要做第一个?有什么区别吗?据我从编译器输出中看到的,至少使用 constexpr 时,没有。如果它们不是 constexpr ,那该怎么办?

Why would you want to do the first one? Are there any differences? As far as I could see from the compiler output, at least with constexpr, there wasn't. What about if they weren't constexpr, would there be any differences in that case?

编辑:注意,似乎使用了与第一个示例非常相似的代码来代替常规功能。 6个不同的结构,都只有 operator()模板,都像示例的最后一行一样被实例化。然后,每个函数都像正常函数一样使用。

As a note, code very similar to the first example was seemingly being used in place of normal functions. 6 different structures, all with only operator() templates, all were instantiated like the last line of the example. Each was then used exactly like a normal function.

推荐答案

有人在注释中建议函数对象可以具有其他状态。确实是这样,但我会更具体一点:您可以创建状态变化的函数对象的多个副本。如果函数对象是单例,则这一点没有意义。函数也可以具有全局变量形式的状态。

Someone suggested in the comments that a function object can have additional state. While this is true, I would be a bit more specific: you can create multiple copies of a function object with varying state. If the function object is singleton, then this point is moot; a function can also have state in the form of global variables.

如果您的函数对象声明为 constexpr ,则其内部状态均不可改变。这使它与 constexpr 函数处于同一位置:调用它可以是一个常量表达式,但前提是它不访问任何非常量表达式 global 状态。

And if your function object is declared constexpr, then none of its internal state can be mutable. This puts it in the same position as a constexpr function: calling it can be a constant expression but only as long as it doesn't access any non-constant-expression global state.

在C ++ 17之前的一个重要区别是函数可以是 inline ,而对象则不能。在C ++ 14中,如果您在标头中定义函子 foo ,则每个翻译单元将有一个副本。如果需要 foo 在所有翻译单元中具有相同的地址,则需要将其声明为 inline 函数。但是在C ++ 17中,函数对象也可以是内联的。

One important difference before C++17 is that functions could be inline, whereas objects could not be. In C++14, if you defined the functor foo in a header, then there would be one copy of it per translation unit. If you needed foo to have the same address in all translation units, you would need to declare it as an inline function. But in C++17, function objects can be inline too.

但是,即使您只有函数对象的一个​​实例,也没有状态,并且如果您使用的是C ++ 17或更高版本,则该函数与函数之间至少还有一个重要区别:可以通过依赖于参数的查找来找到函数,而不能通过函数对象来找到函数。这就是为什么C ++ 20 Ranges库中的某些函数实际上根本不能是函数,而必须是函数对象的原因。这些被非正式地称为 niebloids

But even if you only have a single instance of the function object, and it has no state, and you are using C++17 or later, there is still at least one important difference between that and a function: functions can be found by argument-dependent lookup, whereas function objects cannot. This is the reason why some "functions" in the C++20 Ranges library actually cannot be functions at all, and must be function objects. These are informally referred to as niebloids.

这篇关于仅具有operator()的结构与正常函数之间的实际区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆