According to the accepted answer to a previous post
Declarations are not expressions. There are places where expressions
are allowed, but declararions are not. The left hand side of ?, the
trinary operator, is one of them.
Now, consider the following code segment:
#include <iostream>
using std::cout;
using std::endl;
enum struct status{invalid=0, valid};
status test (void);
int main (void){
status s = test();
cout << static_cast<int>(s) << endl;
return (0);
}
status test (void){
static auto invocation_count = 0;
++invocation_count;
//return (invocation_count % 2) ? (status::invalid) : (status::valid);
(invocation_count % 2) ? (return (status::invalid)) : (return (status::valid));
}
The function test() does not compile (note the compiler error log displays line numbers in the original test code):
g++ -ggdb -std=c++17 -Wall -Werror=pedantic -Wextra -c code.cpp
code.cpp: In function ‘status test()’:
code.cpp:19:31: error: expected primary-expression before ‘return’
(invocation_count % 2) ? (return (status::invalid)) : (return (status::valid));
^~~~~~
code.cpp:19:31: error: expected ‘)’ before ‘return’
code.cpp:19:83: error: expected ‘:’ before ‘;’ token
(invocation_count % 2) ? (return (status::invalid)) : (return (status::valid));
^
code.cpp:19:83: error: expected primary-expression before ‘;’ token
code.cpp:20:1: warning: no return statement in function returning non-void [-Wreturn-type]
}
^
make: *** [makefile:20: code.o] Error 1
However, if the last line inside test(), which is the source of error, were to be commented out and the line above (presently commented out) were to be enabled, the code compiles.
Both the lines use the ternary operator for return switch, albeit differently. And in both cases, the left hand side of the ? inside the ternary operator does not include any declaration (in fact it is the same expression in both cases).
So why does one compile while the other doesn't?
This is a legal expression:
{expression} ? {expression} : {expression}
This is a legal statement:
return {expression};
So:
return (invocation_count % 2) ? (status::invalid) : (status::valid);
is:
return {expression} ? {expression} : {expression};
Which has the form:
return {expression};
That's perfectly legal.
On the other hand consider:
(invocation_count % 2) ? (return (status::invalid)) : (return (status::valid));
This has the form:
{expression} ? {statement} : {statement}
That is not legal because the ?: operator requires expressions before and after the colon.
Parts of ternary operator must be expressions. return is not an expression. It is a statement.
Related
In C++, the following is valid and I can run it without a problem:
int main(){
if (int i=5)
std::cout << i << std::endl;
return 0;
}
However, even though the following should also be valid, it gives me an error:
if ((int i=5) == 5)
std::cout << i << std::endl;
Error:
test.cpp: In function ‘int main()’:
test.cpp:4:10: error: expected primary-expression before ‘int’
if ((int i=5) == 5)
^
test.cpp:4:10: error: expected ‘)’ before ‘int’
test.cpp:5:36: error: expected ‘)’ before ‘;’ token
std::cout << i << std::endl;
^
Furthermore, in C++17 the below code must be valid too, but it gives me a similar error again:
if (int i=5; i == 5)
std::cout << i << std::endl;
Error:
test.cpp: In function ‘int main()’:
test.cpp:4:16: error: expected ‘)’ before ‘;’ token
if (int i=5; i == 5)
^
test.cpp:4:18: error: ‘i’ was not declared in this scope
if (int i=5; i == 5)
^
I am trying to compile with g++ test.cpp -std=c++17. g++ --version gives me g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609. What am I missing here?
if ((int i=5) == 5) is a syntax error. It does not match any supported syntax for if statements. The syntax is init-statement(optional) condition, where condition could either be an expression, or a declaration with initializer. You can read more detail about the syntax on cppreference.
if (int i=5; i == 5) is correct. However, you are using an old version of GCC that dates from before C++17 was standardized. You would need to upgrade your compiler version. According to C++ Standards Support in GCC this feature was added in GCC 7.
For starters, I believe your compiler is right to reject
if ((int i=5) == 5)
because this is not legal C++ code. A variable declaration statement isn’t an expression, so you can’t treat (int i = 5) as an expression.
For the second one, I suspect you just need to update your compiler. g++ 5.6 is a fairly old version at this point, and I believe more updates versions of g++ will handle that code with no problem.
The following code
#include <iostream>
#include <memory>
#include <ios>
using std::cout;
using std::endl;
using std::unique_ptr;
using std::make_unique;
using std::boolalpha;
template<typename T>
struct alloc{
alloc();
unique_ptr<T> operator() (void){
return(auto up = make_unique<T>(NULL));
}
};
int main (void){
auto up = alloc<int>()();
cout << boolalpha << ((up) ? 1 : 0) << endl;
return 0;
}
when compiled gives the following error:
g++ -ggdb -std=c++17 -Wall -Werror=pedantic -Wextra -c code.cpp
code.cpp: In member function ‘std::unique_ptr<_Tp> alloc<T>::operator()()’:
code.cpp:14:16: error: expected primary-expression before ‘auto’
return(auto up = make_unique<T>(NULL));
^~~~
code.cpp:14:16: error: expected ‘)’ before ‘auto’
make: *** [makefile:20: code.o] Error 1
There is an earlier question on SO reporting the same error:
C++17 std::optional error: expected primary-expression before 'auto'
The following is a snippet from the accepted answer to the above question:
Declarations are not expressions. There are places where expressions
are allowed, but declararions are not.
So my questions based on the compilation error I get are:
a) Is the use of a declaration in a return statement not permitted by the standard?
b) What are the permitted contexts for declarations?
Note: I had deliberately used the auto keyword in the return statement to reproduce this error. This error had originally appeared in a larger code base.
TIA
Is the use of a declaration in a return statement not permitted by the standard?
Indeed it isn't. We need only examine the grammar production at [stmt.jump]/1
Jump statements unconditionally transfer control.
jump-statement:
break ;
continue ;
return expr-or-braced-init-listopt ;
goto identifier ;
There is no production that turns an "expr-or-braced-init-list" into any sort of statement, so no declaration statement either. There is also no production that turns it into any other sort of declaration (such as a function, namespace or class). So you cannot declare anything in the return statement's operand.
What are the permitted contexts for declarations?
Almost anywhere an expression isn't required explicitly. The very definition of a translation unit in C++ (one file being translated) is a sequence of declarations per [basic.link]/1.
A program consists of one or more translation units linked together. A
translation unit consists of a sequence of declarations.
translation-unit:
declaration-seqopt
Different declarations have different structure. Somes such as namespaces, may contain more declarations. Others such as functions may contain statements, which themselves may be declaration statements of certain things. But most importantly, the standard makes clear where a statement may appear, and where only an expression is permitted.
I'm trying to compile a program I got from the net. Trying to use in codeblocks but its showing errors. I don't understand what is going wrong. I've looked up in various forums but not much light is shed. Can anyone help soon? Thanks in advance
#include <functional>
#include <iostream>
int print_num(int i, int j) { return i + j; }
int main() {
std::function<int(int, int)> foo = print_num;
std::function<int(int, int)> bar;
try {
std::cout << foo(10, 20) << '\n';
std::cout << bar(10, 20) << '\n';
} catch (std::bad_function_call& e) {
std::cout << "ERROR: Bad function call\n";
}
return 0;
}
These are some of the errors other than 14 other errors saying declaration not done. I guess clearing these error would solve that problem.
main.cpp|10|error: 'function' is not a member of 'std'
main.cpp|10|error: expression list treated as compound expression in functional cast [-fpermissive]
main.cpp|10|error: expected primary-expression before 'int'
You need to compile with -std=c++11 to add in the C++11 features.
$ g++ -std=c++11 test.cxx && ./a.out
30
ERROR: Bad function call
vs:
$ g++ test.cxx && ./a.out
test.cxx: In function ‘int main()’:
test.cxx:10:3: error: ‘function’ is not a member of ‘std’
test.cxx:10:28: error: expression list treated as compound expression in functional cast [-fpermissive]
test.cxx:10:17: error: expected primary-expression before ‘int’
...
I wrote the absolute function using ternary operator as follows
int abs(int a) {
a >=0 ? return a : return -a;
}
I get the following error messages
../src/templates.cpp: In function ‘int abs(int)’:
../src/templates.cpp:4: error: expected primary-expression before ‘return’
../src/templates.cpp:4: error: expected ‘:’ before ‘return’
../src/templates.cpp:4: error: expected primary-expression before ‘return’
../src/templates.cpp:4: error: expected ‘;’ before ‘return’
../src/templates.cpp:4: error: expected primary-expression before ‘:’ token
../src/templates.cpp:4: error: expected ‘;’ before ‘:’ token
../src/templates.cpp:5: warning: no return statement in function returning non-void
If I write like this
return a>=0 ? a : -a;
I don't get any error.
What's the difference between the two?
The second and third arguments to the ternary operator are expressions, not statements.
return a
is a statement
Your syntax is incorrect.
It should be
if (a >=0)
return a;
else
return -a;
or the way you wanted it:
return a >=0 ? a : -a;
What's the difference between the two?
One is correct syntax, the other is not.
?: is an operator that takes three expressions and evaluates them in some way to produce a result. return a is not an expression (it's a statement), so your first form doesn't work. It's the same as you can't put return in the arguments of other operators: return a + return b will also not work.
If you want the returns in the separate branches, use if instead:
if (a >=0)
return a;
else
return -a;
Return is a statement and cannot be used where a value is expected.
You must use expressions (which usually yield a value) in the three components of the ternary operator.
Could anyone help me to understand following line of code:
sol< ?=f((1<< n)-1,i,0)+abs(P[i])*price;
I am studying an algorithm written using c++ and it has following operator < ?= . My problem is with understanding < ?= operator. Also when I compile this code using g++ compiler , it gives error message for above line of code line of code
following is the error message returned.
Hello.cpp: In function ‘int main()’:
Hello.cpp:115: error: ‘memset’ was not declared in this scope
Hello.cpp:142: error: expected primary-expression before ‘?’ token
Hello.cpp:142: error: expected primary-expression before ‘=’ token
Hello.cpp:142: error: expected ‘:’ before ‘;’ token
Hello.cpp:142: error: expected primary-expression before ‘;’ token
Maybe < ?= it is not a single operator, but I can not understand what exactly this line of code does.
Thanks in advance for the time you spent reading this post.
It's a GNU extension. It's basically a "lower than" operator.
int a = 3;
a <?= 2;
cout << a << endl; // prints 2, because 2 < 3
a <?= 10;
cout << a << endl; // prints 2 as well, because 10 > 2
Read more here.
To be clear for anyone reading this and not being able to follow; <?= and >?= are assignment versions of <? and >? which are deprecated GCC extensions which served the purpose of (x>y)?x:y or (x<y)?x:y respectively.
Therefore, x <?= y; would be x = x <? y; which is x = (x<y) ? x : y;
Most compiler vendors introduce language extensions, and many make it into future language standards. Usually these extensions are either just very easy to add or make the job of writing standard libraries much easier.
It could almost be a line of PHP code though: all it needs is remove a space to form at the end.
<?= foo(); ?>
is equivalent to
<?php echo foo(); ?>
Take a look at the C grammar here
The only use of ? is in the ternary operator:
conditional_expression
: logical_or_expression
| logical_or_expression '?' expression ':' conditional_expression
;
Where the ? is followed by an expression. This does not happen in your case. So your code is not a valid C.
This line isn't a line of code. That's why it doesn't compile. It is meaningless to ask what it does.