问题
I have seen code that looks like this:
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;
}
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?
Edit: 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.
回答1:
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.
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.
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.
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.
来源:https://stackoverflow.com/questions/62093977/practical-difference-between-a-struct-with-only-operator-and-a-normal-function