mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-16 07:48:44 +01:00
99 lines
3.4 KiB
Text
99 lines
3.4 KiB
Text
|
||
Add weak_ptr
|
||
Mention namespace chrono_literals
|
||
std::ranges
|
||
rm annotations/OBS/ entries
|
||
|
||
DONE? C++ Annotations: concepts bij 'integral' en 'floating_point' bestaat,
|
||
maar 'numeric' (of vergelijkbaar niet)
|
||
|
||
static operator()
|
||
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1169r4.html
|
||
|
||
2 Motivation
|
||
|
||
The standard library has always accepted arbitrary function objects - whether
|
||
to be unary or binary predicates, or perform arbitrary operations. Function
|
||
objects with call operator templates in particular have a significant
|
||
advantage today over using overload sets since you can just pass them into
|
||
algorithms. This makes, for instance, std::less<>{} very useful.
|
||
|
||
As part of the Ranges work, more and more function objects are being added to
|
||
the standard library - the set of Customization Point Objects (CPOs). These
|
||
objects are Callable, but they don’t, as a rule, have any members. They simply
|
||
exist to do what Eric Niebler termed the “Std Swap Two-Step”. Nevertheless,
|
||
the call operators of all of these types are non-static member
|
||
functions. Because all call operators have to be non-static member functions.
|
||
|
||
What this means is that if the call operator happens to not be inlined, an
|
||
extra register must be used to pass in the this pointer to the object - even
|
||
if there is no need for it whatsoever. Here is a simple example:
|
||
|
||
struct X {
|
||
bool operator()(int) const;
|
||
static bool f(int);
|
||
};
|
||
|
||
inline constexpr X x;
|
||
|
||
int count_x(std::vector<int> const& xs) {
|
||
return std::count_if(xs.begin(), xs.end(),
|
||
#ifdef STATIC
|
||
X::f
|
||
#else
|
||
x
|
||
#endif
|
||
);
|
||
}
|
||
x is a global function object that has no members that is intended to be
|
||
passed into various algorithms. But in order to work in algorithms, it needs
|
||
to have a call operator - which must be non-static: assembly code thus is
|
||
larger than required for non-static op().
|
||
|
||
Proposal:
|
||
|
||
make the call operator a static member function, instead of requiring it to
|
||
be a non-static member function.
|
||
3.1 Overload Resolution
|
||
|
||
There is one case that needs to be specially considered when it comes to
|
||
overload resolution, which did not need to be considered until now:
|
||
|
||
|
||
struct less {
|
||
static constexpr auto operator()(int i, int j) -> bool {
|
||
return i < j;
|
||
}
|
||
|
||
using P = bool(*)(int, int);
|
||
operator P() const { return operator(); }
|
||
};
|
||
|
||
static_assert(less{}(1, 2));
|
||
|
||
If we simply allow operator() to be declared static, we’d have two candidates
|
||
here: the function call operator and the surrogate call function. Overload
|
||
resolution between those candidates would work as considering between:
|
||
|
||
|
||
operator()(contrived-parameter, int, int);
|
||
call-function(bool(*)(int, int), int, int);
|
||
|
||
And currently this is ambiguous because 12.2.4.1 [over.match.best.general]/1.1
|
||
stipulates that the conversion sequence for the contrived implicit object
|
||
parameter of a static member function is neither better nor worse than any
|
||
other conversion sequence. This needs to be reined in slightly such that the
|
||
conversion sequence for the contrived implicit object parameter is neither
|
||
better nor worse than any standard conversion sequence, but still better than
|
||
user-defined or ellipsis conversion sequences. Such a change would
|
||
disambiguate this case in favor of the call operator.
|
||
|
||
|
||
|
||
static operator[]:
|
||
|
||
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2589r1.pdf
|
||
|
||
Stay as close as possible to the behavior of member function operator()
|
||
|
||
|