Global initialization with temporary function object - c++

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.

Related

Visual C++: cast to function type is illegal, g++ also yields an error

My generated code always used unnecessary many parenthesis simply to make certain, that the C++ code was actually doing what the AST expressed. This is first time I'm getting this compiler error, which I cannot explain -- also before I've used custom types.
(define G_ERROR to get an error...)
Visual C++ 2019 yields the following error:
cl -c tmp0.cpp -I ..\Documents\WORK\boost_1_77_0 -DG_ERROR
tmp0.cpp(32): error C2066: cast to function type is illegal
tmp0.cpp(40): error C2675: unary '+': 'abstractValue<32>' does not define this operator or a conversion to a type acceptable to the predefined operator
tmp0.cpp(40): error C2088: '+': illegal for class
g++ v10 yields the following error:
g++-10 -std=c++11 -c tmp0.cpp -I /mnt/c/Users/userName/Documents/WORK/boost_1_77_0/ -DG_ERROR
tmp0.cpp:40:3: error: no match for ‘operator+’ (operand type is ‘abstractValue<>’)
#include <vector>
#include <boost/optional.hpp>
#include <type_traits>
#include <functional>
#include <initializer_list>
#include <set>
struct undetermined
{
};
template<std::size_t SIZE=32>
class abstractValue
{ public:
abstractValue(const double);
abstractValue(const undetermined&);
abstractValue operator+(const abstractValue&) const;
};
struct instance
{
double DTEMP;
abstractValue<> function_231(
std::vector<boost::optional<abstractValue<>> >&_r
) const{
auto &r = _r.at(231);
if (
!r
)r =
#ifdef G_ERROR
(
#endif
abstractValue<>(
undetermined()
)
#ifdef G_ERROR
)
#endif
+(
abstractValue<>(
DTEMP
)
);
return r.value();
}
};
abstractValue<>(undetermined())
Because both abstractValue<> and undetermined are types, there are two interpretations of this without further context:
It is a functional-style explicit cast expression creating a prvalue of type abstractValue<> with (undetermined()) its initializer.
It is a type-id, namely the type of a function returning abstract<> with a single parameter of type "function without parameters returning undetermined" (which is adjusted to "pointer to function without parameters returning undetermined").
You want it to mean the first, not the second. When writing
abstractValue<>(undetermined()) + /*...*/
it cannot have the meaning of 2. and + can only be the binary + operator, but because there are C-style explicit cast expressions in the form of (T)E where T is a type and E an expression, in
(abstractValue<>(undetermined())) + /*...*/
the whole expression could also be such a C-style explicit cast expression with abstractValue<>(undetermined()) being T and +/*...*/ being E with + the unary +.
Because the grammar is ambiguous here, there is a rule saying that any construct that could be interpreted as a type-id in such a situation, is interpreted as a type-id. Therefore the interpretation as 2. is chosen here.
You can avoid this by either simply not using the extra parentheses (as seen they can not always be added without affecting the meaning of an expression) or you can use brace-initialization instead of initialization with parentheses, because braces cannot appear in a function type, disqualifying the 2. immediately in all contexts:
abstractValue<>{undetermined()}
or
abstractValue<>(undetermined{})
or
abstractValue<>{undetermined{}}

Is `auto(expr)` treated as cast at the beginning of the expression statement?

I have a simple code snippet shown below (https://godbolt.org/z/cPT3PhYdj):
int main() {
int x = 1;
auto(1); // ok in GCC, error in Clang
auto{1}; // ok in GCC, error in Clang
static_cast<void>(auto(x)); // ok
auto{x}; // ok in GCC, error in Clang
auto(x); // both error in GCC an Clang
}
Where both GCC and Clang emit an error showing:
// by GCC Trunk [-std=c++23]
<source>: In function 'int main()':
<source>:7:3: error: declaration of 'auto x' has no initializer
7 | auto(x); // why
| ^~~~
Compiler returned: 1
// by Clang Trunk [-std=c++2b]
<source>:3:8: error: expected unqualified-id
auto(1); // why
^
<source>:3:8: error: expected ')'
<source>:3:7: note: to match this '('
auto(1); // why
^
<source>:4:7: error: expected unqualified-id
auto{1}; // why
^
<source>:6:7: error: expected unqualified-id
auto{x}; // why
^
<source>:7:8: error: redefinition of 'x'
auto(x); // why
^
<source>:2:7: note: previous definition is here
int x = 1;
^
<source>:7:8: error: declaration of variable 'x' with deduced type 'auto' requires an initializer
auto(x); // why
^
6 errors generated.
Compiler returned: 1
If C++23 is experimental, and will they be able to fix the ambiguity or change the disambiguation since another auto(expr) is introduced, or just leave it be?
Are these expressions supposed to be parsed as explicit type decay conversion auto(expr) or auto{expr} in expression statements or parsed as a declaration?
If there is no ambiguity, then which priority comes first:
auto(identifier) as auto identifier?, or
auto(identifier) as cast expression?
From Explicit cast conversion:
auto ( expression ) (8) (since C++23)
auto { expression } (9) (since C++23)
8,9) The auto specifier is replaced with the deduced type of the invented variable x declared with auto x(expression); (which is never interpreted as a function declaration) or auto x{expression}; respectively. The result is always a prvalue of an object type.
So your usage seems to be allowed(in accordance with ) by the above quoted statement.
Here is a working demo of your code. Note in the linked demo, only the usage auto(x) produces an error, all other cases work fine.
Also note that from PR105516:
auto(x); is interpreted as auto x;. Use +auto(x); if you want that to be an expression.
If there is no ambiguity, then which priority comes first:
This is one of the examples showing how C++ is a context sensitive language. A construct cannot always be understood without knowing its wider contexts. Consider the following example:
int main()
{
int x = 0 ;
int k ;
//------vvvvvvv----->here auto(x) is behaves as an expression as it is used as an expression
k = auto(x) ;
auto(p) ; //this a declaration and not an explicit case unlike the above
}
As far as I can tell the paper introducing this feature didn't make any further relevant changes except to allow auto as type specifier in a functional-style explicit cast.
So intuitively auto here should behave the same as any other type specifier would.
For example, replacing auto with int, it is expected that all of these cases work and are functional-style explicit casts, except
int(x); // auto(x);
This one could according to the grammar also be a declaration of a variable named x of type int (or placeholder type) with parentheses around the declarator and without initializer.
As usual, the grammar is disambiguated by preferring the interpretation as declaration (see [stmt.ambig]/1). At least, I don't think that it should be different for auto. A declaration with auto placeholder type requires an initializer, which is not present in this interpretation, but according to [stmt.ambig]/3 the disambiguation is supposed to be done very early and purely syntactic even if it ends up in an ill-formed declaration. I am not completely sure but I guess this should mean that auto(x); should still be disambiguated as a declaration.
I don't know why Clang gives errors for many of the other lines. I suppose the feature is either implemented only partially or these are implementation bugs (it is a very new feature in an unfinished standard revision).
I think auto(x) (where x is literally an identifier) can still have different meanings in different contexts and thus is subject to [dcl.ambig.res] in C++23.
Unfortunately, the ambiguity is unlikely to be fixed. In the following program (well-formed since C++11), auto(x) = Bar{}; is interpreted as a declaration. If auto(x) were "fixed", auto(x) = Bar{}; would become an expression statement, which would change the existing behavior.
#include <cstdio>
struct Bar {
Bar()
{
std::puts("initialization");
}
};
struct Foo {
void operator=(Bar)
{
std::puts("assignment");
}
};
int main()
{
Foo x{};
{
auto(x) = Bar{}; // only prints "initialization"
}
}

Why can't one compare a function pointer to a template function without explicit & on function name?

Consider the following code:
void func(int) {}
template<typename T> void templatedFunc(T) {}
int main()
{
void (*p)(int) = func;
bool test1 = p==func;
//bool test2 = p==templatedFunc<int>; // compilation error
bool test3 = p==&templatedFunc<int>; // but this works
}
If you uncomment the test2 line and try to compile the code with g++, you'll get the following error:
test.cpp: In function ‘int main()’:
test.cpp:8:21: error: assuming cast to type ‘void (*)(int)’ from overloaded function [-fpermissive]
bool test2 = p==templatedFunc<int>; // compilation error
^~~~~~~~~~~~~~~~~~
I get this result on g++ 5.3.0 and 6.2.0. At the same time, compilation with clang++ 3.6.0 succeeds without warnings.
Which compiler is correct according to the Standard here — g++, which gives an error or clang++, which doesn't?
And if g++ is right, then why is there such an asymmetry with normal functions vs templated functions regarding the need of explicit address-of operator?
This is a gcc bug, and you are in a corner case, in the C++ standard, Address of overloaded function §13.4 ([over.over]/1):
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a
pointer to function or a pointer to member function for a specific function from the overload set. A function
template name is considered to name a set of overloaded functions in such contexts. The function selected
is the one whose type is identical to the function type of the target type required in the context. [ Note:
That is, the class of which the function is a member is ignored when matching a pointer-to-member-function
type. — end note ] The target can be:
(1.1) — an object or reference being initialized (8.5, 8.5.3, 8.5.4),
(1.2) — the left side of an assignment (5.18),
(1.3) — a parameter of a function (5.2.2),
(1.4) — a parameter of a user-defined operator (13.5),
(1.5) — the return value of a function, operator function, or conversion (6.6.3),
(1.6) — an explicit type conversion (5.2.3, 5.2.9, 5.4), or
(1.7) — a non-type template-parameter (14.3.2).
The overloaded function name can be preceded by the & operator. An overloaded function name shall not
be used without arguments in contexts other than those listed. [ Note: Any redundant set of parentheses
surrounding the overloaded function name is ignored (5.1). — end note ]
Do you see what is lacking in the list from (1.1) to (1.7)... built-in operators!
If you declare an overload of operator == both gcc will not complain with the comparison, more than that you do not have to explicitly specialize the template function:
void func(int) {}
template<class T>
void templatedFunc(T) {}
struct s{};
bool operator==(s, void(*)(int)){return false;}
int main()
{
void (*p)(int) = templatedFunc;
bool test1 = p==func;
bool test2 = s{} == templatedFunc<int>; // no error - no overload resolution
bool test3 = s{} == templatedFunc; // no error - overload resolution
bool test4 = p == templatedFunc<int>; // gcc error, but not an error -
// no overload resolution
//bool test5 = p == templatedFunc; // error - overload resolution not
// performed for built-int operators
}
test2 and test3 compiles with gcc. test4 does not compile on gcc, but there are no overload resolution, you explicitly specialized the function. It really should compile. test5 does not compile as stated in the standard. In this case gcc produces the exact same error message as for test4. This is surely a gcc bug.

g++ rejects, clang++ accepts: foo(x)("bar")("baz");

Somebody had asked the other day why something compiles with clang, but not with gcc. I intuitively understood what was happening and was able to help the person, but it got me wondering -- according to the standard, which compiler was correct? Here is a boiled down version of the code:
#include <iostream>
#include <string>
class foo
{
public:
foo(const std::string& x):
name(x)
{ }
foo& operator()(const std::string& x)
{
std::cout << name << ": " << x << std::endl;
return (*this);
}
std::string name;
};
int main()
{
std::string x = "foo";
foo(x)("bar")("baz");
return 0;
}
This compiles fine with clang++, but g++ gives the following error:
runme.cpp: In function ‘int main()’:
runme.cpp:21:11: error: conflicting declaration ‘foo x’
foo(x)("bar")("baz");
^
runme.cpp:20:17: error: ‘x’ has a previous declaration as ‘std::string x’
std::string x = "foo";
If I add a pair of parentheses in line 21, g++ is happy:
(foo(x))("bar")("baz");
In other words, g++ interprets this line as:
foo x ("bar")("baz");
Methinks itsa bug in g++, but again, I wanted to ask the standard experts, which compiler got it wrong?
PS: gcc-4.8.3, clang-3.5.1
As far as I can tell this is covered in the draft C++ standard section 6.8 Ambiguity resolution which says that there can be an ambiguity between expression statements and declarations and says:
There is an ambiguity in the grammar involving expression-statements
and declarations: An expression statement with a function-style
explicit type conversion (5.2.3) as its leftmost subexpression can be
indistinguishable from a declaration where the first declarator starts
with a (. In those cases the statement is a declaration. [ Note: To
disambiguate, the whole statement might have to be examined to
determine if it is an expression-statement or a declaration. This
disambiguates many examples. [ Example: assuming T is a
simple-type-specifier (7.1.6),
and gives the following examples:
T(a)->m = 7; // expression-statement
T(a)++; // expression-statement
T(a,5)<<c; // expression-statement
T(*d)(int); // declaration
T(e)[5]; // declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration
and then says:
The remaining cases are declarations. [ Example:
class T {
// ...
public:
T();
T(int);
T(int, int);
};
T(a); // declaration
T(*b)(); // declaration
T(c)=7; // declaration
T(d),e,f=3; // declaration
extern int h;
T(g)(h,2); // declaration
—end example ] —end note ]
It seems like this case falls into the declaration examples in particular the last example seems to make the case in the OP, so gcc would be correct then.
Relevant section mentioned above 5.2.3 Explicit type conversion (functional notation) says:
[...] If the type specified is a class type, the class type shall be complete. If the expression
list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1),
and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some
invented temporary variable t, with the result being the value of t as a prvalue.
and 8.3 Meaning of declarators which says:
In a declaration T D where D has the form
( D1 )
the type of the contained declarator-id is the same as that of the
contained declarator-id in the declaration
T D1
Parentheses do not alter the type of the embedded declarator-id, but
they can alter the binding of complex declarators.
Update
I was originally using N337 but if we look at N4296 section 6.8 was updated an it now includes the following note:
If the statement cannot syntactically be a declaration, there is no ambiguity, so this rule does not
apply.
which means that gcc is incorrect since:
foo x ("bar")("baz");
can not be a valid declaration, I originally interpreted paragraph 2 as saying if you case begins with any of the following then it is declaration, which is perhaps how the gcc implementor interpreted as well.
I should have been more suspicious of paragraph 2 since the only normative part of paragraph 2 really said nothing with respect to paragraph 1 and seems to place a requirement on an example which is not normative. We can see that that statement form paragraph 2 is now actually a note which makes much more sense.
As T.C. noted below, paragraph 2 was actually never normative, it just appeared that way and he linked to the change that fixed it.
If we remove the line
std::string x = "foo";
then g++ complains about:
foo(x)("bar")("baz");
with the syntax error:
foo.cc:20:18: error: expected ',' or ';' before '(' token
foo(x)("bar")("baz");
I do not see how foo (x)("bar")("baz"); could be a valid declaration, and apparently g++ can't either. The line foo x("bar")("baz"); is rejected with the same error.
The "ambiguity resolution" mentioned in Shafik's post only kicks in when the expression-statement is syntactically indistinguishable from a declaration. However in this case it is not a valid declaration syntax so there is no ambiguity, it must be an expression-statement.
g++ fails to process the line as an expression-statement so it is a g++ bug.
This is eerily similar to this g++ bug recently discussed on SO; it seems that g++ is perhaps deciding too soon in processing that the line must be a declaration .

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

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>(()).