0

All of the following expressions compile fine:

void();
void(5);
void("hello");
void(std::string("world"));
void(std::vector<int>{1, 2, 3});

Does this mean that any type can be converted to void? That is void is constructible from an argument of any type.

However the following function doesn't compile:

void func()
{
    return std::vector<int>{1, 2, 3};
}

But if I convert the return value to void explicitly, it compiles:

void func()
{
    return void(std::vector<int>{1, 2, 3});
}

Does it mean that all void constructors are explicit?


The answer

Yes, a value of any type can be explicitly converted to void.

Section 3.9.1/9, N3797:

The void type has an empty set of values. The void type is an incomplete type that cannot be completed. It is used as the return type for functions that do not return a value. Any expression can be EXPLICITLY converted to type cv void (5.4). An expression of type void shall be used only as an expression statement (6.2), as an operand of a comma expression (5.18), as a second or third operand of ?: (5.16), as the operand of typeid, noexcept, or decltype, as the expression in a return statement (6.6.3) for a function with the return type void, or as the operand of an explicit conversion to type cv void.

anton_rh
  • 8,226
  • 7
  • 45
  • 73
  • 2
    One way to think about `void( ... )` is compute the `...` including all side-effects and then throw the result away. `void` is a keyword https://en.cppreference.com/w/cpp/language/types#Void_type All of the code above in the form `void( ... )` is a c-style-cast to `void` see (2) here https://en.cppreference.com/w/cpp/language/explicit_cast – Richard Critten May 22 '22 at 12:12
  • 1
    `void` Doesn't have any constructors (no fundamental type does). The behaviour of the expression is specified explicitly, and doesn't depend on the arguments. – StoryTeller - Unslander Monica May 22 '22 at 12:15
  • 1
    @RichardCritten Correction, it's *functional* cast, not C-style cast – user202729 May 22 '22 at 12:33
  • 1
    Not strictly the same question, but it should address most of them [c++ - What does casting to `void` really do? - Stack Overflow](https://stackoverflow.com/questions/34288844/what-does-casting-to-void-really-do) – user202729 May 22 '22 at 12:34
  • @user202729 just paraphrasing CPP reference _"... This cast expression is exactly equivalent to the corresponding C-style cast expression...."_ https://en.cppreference.com/w/cpp/language/explicit_cast – Richard Critten May 22 '22 at 13:02
  • `void` has a deeper meaning, especially in functional programming, where the C++ void is a singleton value (and the Void is something different/absurd). See https://bartoszmilewski.com/2014/11/24/types-and-functions/ -> section *Examples of Types*. The Curry-Howard isomorphism connects the type system with logical expressions and proofs (https://en.m.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence) – Sebastian May 22 '22 at 13:03
  • 1
    "constructible" is not the right word. `void()` in your example is a function type, the rest are casting values to `void`, which doesn't do anything. – Aykhan Hagverdili May 22 '22 at 13:15
  • @AyxanHaqverdili, no, it's not a function type, it's constructing of void value: [link](https://coliru.stacked-crooked.com/a/a39d54e3586a043e). – anton_rh May 22 '22 at 17:44

1 Answers1

1

As said in the comment, "One way to think about void( ... ) is compute the ... including all side-effects and then throw the result away"

The same can be seen using a contrived example:

struct C 
{
    C(int) 
    {
        std::cout<<"converting constructor called"<<std::endl;
    }
};
int main()
{
    void(C(5)); //prints converting constructor called
    
}

The ones you provided are explicit type conversions and can be understood using explicit cast which states:

new-type ( )  (4)     

If new-type names a non-array complete object type, this expression is an prvalue of type new-type, designating a temporary (until C++17)whose result object is (possibly with added cv-qualifiers) (since C++17) of that type. If new-type is an object type, the object is value-initialized. If new-type is (possibly cv-qualified) void, the expression is a void prvalue without a result object (since C++17).

(emphasis mine)

The above is for the first case in your example void().


The rest of them are functional cast expression which are exactly equivalent to the corresponding C-style cast expression.

new-type ( expression )   (2)     

The functional cast expression consists of a simple type specifier or a typedef specifier (in other words, a single-word type name: unsigned int(expression) or int*(expression) are not valid), followed by a single expression in parentheses. This cast expression is exactly equivalent to the corresponding C-style cast expression.


The standard also states:

Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression.

An expression of type cv void shall be used only as an expression statement (9.2), as an operand of a comma expression (8.19), as a second or third operand of ?: (8.16), as the operand of typeid, noexcept, or decltype, as the expression in a return statement (9.6.3) for a function with the return type cv void, or as the operand of an explicit conversion to type cv void.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Functional cast is `new-type ( expression )`, not `new-type ( )` which is what you showed in the reference quote. – interjay May 22 '22 at 12:47