The following code prints nullptr instead of empty (godbolt link):
#include <iostream>
class empty { };
#if 1
void f(std::nullptr_t) {
std::cout << "nullptr\n";
}
#endif
void f(empty) {
std::cout << "empty\n";
}
int main() {
f({});
}
Disabling the f(nullptr_t) variant causes empty to be printed. What are the rules C++ is using to select the nullptr_t variant over the empty variant when both are available?
Initializing std::nullptr_t (or any other fundamental type) with {} is better because it result in an identity conversion, whereas initializing class types results in a user-defined conversion sequence:
Otherwise, if the parameter has an aggregate type which can be initialized from the initializer list according to the rules for aggregate initialization ([dcl.init.aggr]), the implicit conversion sequence is a user-defined conversion sequence whose second standard conversion sequence is an identity conversion.
- [over.ics.list] p8
empty is an aggregate type, so this paragraph applies. std::nullptr_t is not a class, so the following paragraph applies:
Otherwise, if the parameter type is not a class:
- (10.1) [...]
- (10.2) if the initializer list has no elements, the implicit conversion sequence is the identity conversion.
- [...]
- [over.ics.list] p10
[over.best.ics] explains which implicit conversion sequence is better, but it should be obvious that an identity conversion beats everything else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With