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()
, whereT
is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified)void
type, 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