Why doesn't this C++ expression generate even a warning? - c++

I know you can supress the "expression without effect" warning casting an expression to void:
int main()
{
void(2+3);
}
If I'm not wrong, the meaning of casting something to void is not casting the expression to an object of type void (void is a type with no objects, or better said, an empty set), but telling the compiler we want ignore the value of the expression. Other related sample:
int main()
{
(void)(2+3);
}
there's any semantic difference between this and the other sample?
And finally:
int main()
{
void();
}
which returns no warnings (here the Coliru test, full of pedantic.related options); however, this other generates an error:
int main()
{
(void)();
}
// Error:
// main.cpp:6:9: error: expected primary-expression before 'void'
// (void)();
// ^
// main.cpp:6:9: error: expected ')' before 'void'
What's the meaning of the void() expression? Are you creating a temporary object of type void, which have no sense?, or are you casting an empty expression to void?
And in general, I would like to understand the complete picture about the usage of void, and which behavour/semantic is the one specified by the standard.

This void(2+3) is not a cast, it's a pseudo constructor. Yes, there's a semantic difference between void(2+3) and (void)(2+3). void(2+3) is a construction with an implicit cast like: void((void)(2+3)). void() is also a legal pseudo construction, though with a pseudo default-constructor rather than a pseudo copy-constructor.
Yes void() is essentially creating a temporary with the type void (though as you say you can't actually have objects of void type, so you can never do anything with it; it can't be passed as a parameter, assigned to a variable, etc.)
Casts operate on expressions: (void) (2+3) operates on the expression (2+3). But () is not a legal expression, so (void)() is not legal. Similarly you cannot do static_cast<void>() or static_cast<void>(()).

Related

How to convert a variable from an int into a template parameter only if it is convertable in c++

I am trying to write a function that takes a variable of arbitrary type and sets it to an int value only if the type of the given variable can be converted to an int. My simplified code:
template <typename T>
void getInt(T& param)
{
int int_value = calculate_int_value();
if(std::is_convertible_v<int, T>){
param = static_cast<T>(int_value);
}
}
However, when I try to compile it, I get errors such as
error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(int&)'
error: invalid conversion from 'int' to 'const char*'
Which makes me think I can't just convert an int value of arbitrary type inside an if statement, which proves it convertibility. How do I achieve my goal? Did I miss something?
std::is_convertible_v was added in C++17, if your code uses it then this means that your compiler support C++17, which also has if constexpr:
if constexpr(std::is_convertible_v<int, T>){
param = static_cast<T>(int_value);
}
In a regular if, even if it always evaluates to false, whatever's in the if statement must still be valid C++. Even if the body of a regular if statement is never executed it still must compile as valid C++. Attempting to convert something to int when it is proven not to be convertible to an int will, of course, not work.
if constexpr makes it possible to do otherwise (as long as if itself is a compile-time constant expression). The body of the if statement must still be syntactically valid C++, but only syntactically valid.

GCC allows arrays to be returned from function - bug or feature?

I was amazed to find out that GCC allows functions to return arrays when trailing return type is used instead of normal one. As you probably knows arrays can't be copied so this is quite limited but let me show you some cool example.
#include <iostream>
#include <typeinfo>
using namespace std;
auto func() -> int [5]
{
return {4, 56, 78, 4, 0};
}
int main()
{
cout << func()[2] << endl;
cout << typeid(func).name() << endl;
}
Is this a compiler bug or some new feature?
Interestingly 'typeid' returns 'FA5_ivE' which is demangled as 'int (()) [5]' and this means exactly what you think an function returning array of 5 int's.
EDIT: I tried bounding the returned array into rvalue reference but without any success (used most of the possible forms):
auto &&refArrayTemp{ func() };
Seems that this extensions is rather useless.
This was a bug in gcc (fixed as of 2017-07-03), caused by inconsistent treatment of trailing-return-types.
First note the difference in error message between two attempts to declare a function returning a function:
using Fv = void();
Fv f1(); // error: 'f1' declared as function returning a function
auto f2() -> Fv; // error: function return type cannot be function
The first error comes from decl.c, handling declarators, while the second is a lot deeper into the internals, from tree.c, attempting to build the function type preparatory to generating code.
Trailing-return-types are handled in decl.c 30 lines below the above error - too late to catch it with the above error code, and it is not handled separately.
With arrays, similarly using a trailing-return-type allows us to skip the checks in decl.c, the difference being that function-returning-array is actually valid in terms of gcc's internal representation.
Note that you can't do much with it; gcc doesn't allow you to assign, reference-bind, decay or pass the result of func() to another function:
auto a1 = func();
// error: invalid use of non-lvalue array
auto& a2 = func();
// error: invalid initialization of non-const reference of type 'int (&)[5]' from an rvalue of type 'int [5]'
auto&& a3 = func();
// error: lvalue required as unary '&' operand
Indeed, even your code is rejected at -Wpedantic:
warning: ISO C++ forbids subscripting non-lvalue array
Finally, by exploiting a similar bug (qualifiers are stripped from scalars before handling of trailing-return-types) we can create a function with type int const volatile():
int const volatile g1(); // warning: type qualifiers ignored on function return type
auto g2() -> int const volatile; // OK!!
Latest draft, [dcl.array]/p10:
Functions shall not have a return type of type array or function, although they may have a return type of
type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays
of pointers to functions.
This could be a non-standard GCC extension. It doesn't compile in the trunk version of clang. However, this may also be a bug since it has inconsistent behavior with a non-trailing return type.

Global initialization with temporary function object

The following code
#include <random>
std::mt19937 generator((std::random_device())());
compiles just file with clang:
$ clang++ -c -std=c++0x test.cpp
but fails with gcc:
$ g++ -c -std=c++0x test.cpp
test.cpp:3:47: erro: expected primary-expression before ‘)’ token
Is that code valid in C++11? Is it a bug in GCC or a extension/bug of Clang?
gcc is parsing the subexpression (std::random_device())() as a cast to the function type std::random_device(). It helps to look at icc's error output, which is slightly more informative than gcc's:
source.cpp(6): error: cast to type "std::random_device ()" is not allowed
std::mt19937 generator((std::random_device())());
^
source.cpp(6): error: expected an expression
std::mt19937 generator((std::random_device())());
^
The relevant production is 5.4p2:
cast-expression:
unary-expression
( type-id ) cast-expression
Since an empty pair of parentheses () is not a unary-expression, this production is unavailable and the compiler should select the production from 5.2p1:
postfix-expression:
[...]
postfix-expression ( expression-listopt )
[...]
where the postfix-expression is (std::random_device()) and the expression-list is omitted.
I've filed http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56239 on gcc bugzilla, and it looks like it should be resolved shortly.
Note that if you are supplying arguments to the operator() then the compiler is required by 8.2p2 to parse the expression as a cast, even though it is illegal to cast to a function type (if there are multiple arguments, the argument list is parsed as an expression using the comma operator:
(std::less<int>())(1, 2);
^~~~~~~~~~~~~~~~~~ illegal C-style cast
^~~~~~~~~~~~~~~~ type-id of function type std::less<int>()
^~~~~~ argument of C-style cast
^ comma operator
The correct way to write this (other than using C++11 universal initializer syntax) is to add another layer of parentheses, since a type-id cannot contain outer parentheses:
((std::less<int>()))(1, 2);
Seems like there is problem with the way GCC handles function declarations. Take this example:
struct A
{
bool operator () () { return true; }
};
struct B
{
B(bool) { }
};
B b(( // This cannot be parsed as a function declaration,
A()() // and yet GCC 4.7.2 interprets it as such:
)); // "error: 'type name' declared as function returning
// a function B b((A()()));"
int main() { }
Due to the presence of additional parentheses around A()(), the syntactic form B b(( A()() )); cannot be parsed as a declaration of a function.
The declaration in your question's example is slightly different:
B b(
(A())()
);
Even in this case, though, (A())() cannot be interpreted as the type of a function which returns a function that returns A (always in an attempt to consider b as a function declaration with an unnamed parameter). So the question is: can it be interpreted as anything else? If so, and if its meaningful in this context, then the compiler should consider to parse the whole expression as the construction of object b.
This is probably the fundamental point where GCC and Clang disagree:
int main()
{
(A())(); // OK for Clang, ERROR for GCC
}
I do not see how the above could be interpreted as anything else than an attempt to construct a temporary of type A and invoke its call operator. It cannot be a function declaration, because if A is interpreted as the return type, then the name is missing (and vice versa).
On the other hand, (A()) is a valid expression for creating a temporary of type A, and that temporary supports the call operator (whose return type is the same as the type accepted by B's constructor). Thus, (A())() should be a valid expression of type bool.
For this reasons, I believe that GCC's parsing is wrong.

function pointers and return type conversions

Suppose I have a function that performs some side effect and then returns an answer:
int foo()
{
perform_some_side_effect();
return 42;
}
I want to bind foo to a function pointer, but I'm not interested in the answer, just the side effect:
void (*bar)() = foo;
However, this appears to be a type error:
error: invalid conversion from ‘int (*)()’ to ‘void (*)()’
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
On a side note, it works if I wrap the function pointer in a std::function:
std::function<void()> baz = foo;
How does std::function (apparently) manage to circumvent this restriction in the type system?
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
The reason is that the types are different, and the generated code at the place of call (through the function pointer) is different. Consider a calling convention where all arguments are written to the stack and space for the return value is also reserved in the stack. If the call goes through a void (*)() then no space will be reserved in the stack for the return value, but the function (unaware of how it is being called) will still write the 42 to the location where the caller should have reserved space.
How does std::function (apparently) manage to circumvent this restriction in the type system?
It does not. It creates a function object that wraps the call to the actual function. It will contain a member like:
void operator()() const {
foo();
}
Now when the compiler processes the call to foo it knows what it has to do to call a function that returns an int and it will do so according to the calling convention. Because the template does not return, it will just ignore the value --that was actually returned.
std::function need only be source compatible- that is, it can generate a new class which generates new caling code that ignores the result. The function pointer must be binary compatible and cannot do that job- void(*)() and int(*)() point to the exact same code.
You can think of std::function<> doing this for your particular case:
void __func_void()
{
foo();
}
It's actually a bit more complicated than that, but the point is that it generates template code together with type-erasure to not care about the specifics.
In addition to what others have been saying, the caller also need the return type to know what destructor it should invoke on the result (the return value may be a temporary).
Unfortunately it is not as easy as
auto (*bar)() = foo;
Although GCC and Clang accept this. I need to recheck the spec to see whether that's actually correct.
Update: The spec says
The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer or that a function declarator shall include a trailing-return-type.
This can be misleading when read fast, but this is implemented by GCC and clang to only apply to the toplevel declarator. In our case, this is a pointer declarator. The declarator nested in it is a function declarator. So just substitute auto for void and then the compiler will deduce the type for you.
By the way, you can always make this work manually, but it takes some trickery to make it work
template<typename FunctionType>
struct Params;
template<typename ...Params>
struct Params<void(Params...)> {
template<typename T>
using Identity = T;
template<typename R>
static Identity<R(Params...)> *get(R f(Params...)) {
return f;
}
};
// now it's easy
auto bar = Params<void()>::get(foo);

Can typeid() be used to pass a function?

I tried this and got the output as:
void
Please explain the following Code:
#include <cstdio>
#include <typeinfo>
using namespace std ;
void foo()
{ }
int main(void)
{
printf("%s",
typeid(foo()).name());// Please notice this line, is it same as typeid( ).name() ?
return 0;
}
AFAIK:
The typeid operator allows the type of an object to be determined at run time.
So, does this sample code tell us that a function that returns void is of **type void**.
I mean a function is a method and has no type. Correct?
typeid does not work with objects. It works with expressions.
typeid returns the type of the expression you supply to it as an argument. The expression can refer to an object, or to something that is not an object. You supplied expression foo() as an argument. This expression has type void. So, you got a result that refers to type void. void, BTW, is not an object type.
Function do have types. If you want to apply typeid to the function itself, the syntax would be typeid(foo). The function-to-pointer conversion is not applied to the argument of typeid, which means that you should get a result that refers to function type itself. Meanwhile, typeid(&foo) will give you a function pointer type id, which is different from typeid(foo).
That is telling you the type of the function's return.
To get the type of the function itself, you want:
typeid(foo) // note the lack of ()
Wrong on both counts.
1) The sample code tells you that the type of the result of calling foo() is void.
2) Functions are also types.