I have recently seen some SFINAE-based code that looks like this:
template <typename T>
auto test(T &myclass) -> decltype(myclass.f(), void())
{
// do something here, don't return anything (void)
}
Basically the function above uses SFINAE to reject all parameters of type T that don't have f() as a member function. The SFINAE takes place in the decltype, where we have 2 expressions separated by the comma operator. If the first expression cannot be evaluated, SFINAE kicks in and rejects the overload. If the expression can be evaluated, then, because of the comma operator, void is being returned from the function.
As far as I understand, void() "constructs" a void object in an un-evaluated context (yes, this is legal), which is then picked by the decltype so void is the return type of the function.
My question is: why cannot we use void{} instead? Doesn't it have the same effect of "constructing" a void object in an un-evaluated context? My compiler(s) (g++/clang++) don't accept the void{} code
error: compound literal of non-object type 'void'(g++4.9/g++5)
and
error: illegal initializer type 'void'(clang++ 3.5)
It's an expression. [expr.type.conv]/p2-3:
The expression
T(), whereTis a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified)voidtype, creates a prvalue of the specified type, whose value is that produced by value-initializing (8.5) an object of typeT; no initialization is done for thevoid()case. [Note: ... - end note]Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4) with the specified braced-init-list, and its value is that temporary object as a prvalue.
You can't create a temporary object of type void. void() is a special exception that allows you to make a void prvalue.
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