Permitted usage context of declarations - c++

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.

Related

Ambiguous Function Call when One Definition is in a Namespace

I have a simple program containing the following code:
namespace nam
{
struct S{};
void f(S *){}
}
void f(nam::S *){}
int main()
{
nam::f(nullptr);
nam::S s;
f(&s);
return 0;
}
I expect that this will compile fine because I am calling f the second time without specifying namespace nam. However, upon compiling the code, I get this error:
$ g++ main.cpp -std=c++11 -Wall -Wextra
main.cpp: In function ‘int main()’:
main.cpp:14:9: error: call of overloaded ‘f(nam::S*)’ is ambiguous
f(&s);
^
main.cpp:7:6: note: candidate: void f(nam::S*)
void f(nam::S *){}
^
main.cpp:4:10: note: candidate: void nam::f(nam::S*)
void f(S *){}
Compiler and version:
$ gcc --version
gcc (Debian 5.3.1-14) 5.3.1 20160409
After trying this with different compilers, similar errors are returned. This seems to be a defined part of C++. I can't find anywhere on the internet where it says that calling a function with a struct in namespace nam as a parameter effectively implies using namespace nam; and requires ::f to remove ambiguity. I have 2 questions about this:
Where is this defined in the C++ standard?
Is there a good reason for this behavior?
Personally I like to avoid using namespace x; and similar. I want the compiler to give me an error when I don't specify a namespace. This behavior stops the compiler from doing so, and this means my code is inconsistent in places, because I occasionally forget to specify the namespace when calling functions like f that are not declared globally anywhere.
Your implementation of f(nam::S*) is outside of the namespace of 'nam'
change:
void f(nam::S *){}
to:
void nam::f(nam::S *){}
(or just move the enclosing namespace bracket) and all should be fine.
if your call to f(&s) in the current namespace was intentional then you need to specify this by changing the function call to
::f(&s)
As was said in the comments, this is due to argument-dependent lookup. I guess now I'll have to figure out now if I want to always specify the namespace in my code where this would make it unnecessary, or never specify it.

Program without semicolon compiles fine in C not in C++ why?

I am using Orwell Dev C++ IDE. Recently I tested following simple program in which I forgot to put semicolon (;) but still it compiles fine in C but not in C++. Why? What is the reason?
// C program compiles & runs fine, even ; missing at end of struct
#include <stdio.h>
struct test
{ int a,b}; // missing semicolon
int main()
{
struct test d={3,6};
printf("%d",d.a);
return 0;
}
[Warning] no semicolon at end of struct or union [enabled by default]
// Following is compilation error in C++
#include <stdio.h>
struct test
{ int a,b}; // missing semicolon
int main()
{
struct test d={3,6};
printf("%d",d.a);
return 0;
}
[Error] expected ';' at end of member declaration
I also tried same C program in codeblocks 13.12 IDE but it shows following error message
error: no semicolon at end of struct or union.
Why different error messages given by different implementations?
The semicolon is required by both languages. Specifically, C specifies the declaration of one or more structure members as
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
and C++ specifies the declaration of one or more class member variables as
member-declaration:
attribute-specifier-seq<opt> decl-specifier-seq<opt> member-declarator-list<opt> ;
both of which require a semicolon at the end.
You'll have to ask the compiler writers why their C++ compiler is more strict than their C compiler. Note that the language specifications only require a "diagnostic" if a program is ill-formed, so it's legitimate either to issue a warning and continue compiling as if the semicolon were present, or to issue an error and stop.
It looks like your IDE is using GCC as its compiler; in which case you could use -Werror to convert warnings into errors, if you'd prefer stricter diagnostics.

Overkilling "crosses initialization of variable" error in C++?

I noticed that g++ complain a bit too strictly about crossed initialization and I wonder why these false-positive errors could not be removed just by looking at the SSA form of the program while compiling.
Let me give a very simple example:
#include <cstdlib>
int main ()
{
goto end;
int i = 0; // unused variable declaration
end:
return EXIT_SUCCESS;
}
When compiled with g++ -Wall -Wextra -o example1 example1.cc (g++ 4.8.1), the compiler gives the following error message:
example1.cc: In function ‘int main()’:
example1.cc:10:2: error: jump to label ‘end’ [-fpermissive]
end:
^
example1.cc:6:8: error: from here [-fpermissive]
goto end;
^
example1.cc:8:7: error: crosses initialization of ‘int i’
int i = 0;
^
example1.cc:8:7: warning: unused variable ‘i’ [-Wunused-variable]
So, it will raise an error where there is actually no risk because the variable is unused (the compiler obviously has both information and cannot combine it to deduce that the error is a false-positive).
More strange, I hoped that LLVM was more efficient at analyzing a program. So, I tried clang++ (LLVM) on this simple example with clang++ -Wall -Wextra -o example1 example1.cc (clang++ 3.4). And, I got about the same error message:
example1.cc:8:7: warning: unused variable 'i' [-Wunused-variable]
int i = 0;
^
example1.cc:6:3: error: goto into protected scope
goto end;
^
example1.cc:8:7: note: jump bypasses variable initialization
int i = 0;
^
1 warning and 1 error generated.
So, I am pretty sure that I am missing something important here, a problem that make the detection of this false-positive harder than I though. But, I do not know what is it. Or maybe, the C++ specification specifically says that it must be like this.
If somebody has an idea, feel free to share !
Edit: I also compiled the exact same code in C (gcc or clang), and it went fine just with the warning about i being an unused variable. So, it reinforce the fact that this is more likely linked to the specification of C++ and not a problem detecting this issue at compile time.
There is nothing wrong with the compilers. Your code is ill-formed according to the standard.
In your particular case, the requirement of the standard may not be necessary and the jump could be allowed and the compiler could create valid code. However, this is only because the initialisation of the variable int i has no side effects.
You can make your code valid by simply enclosing the jumped section in its own scope:
#include <cstdlib>
int main ()
{
goto end;
{
int i = 0; // unused variable declaration
}
end:
// cannot use i here, as it's not defined.
return EXIT_SUCCESS;
}
This is disallowed because potentially you'd call destructors for objects that aren't properly constructed. Admittedly, int doesn't have constructor or destructor, but it's making it "fair" for all types of objects. And technically, something at label end: could be using i, and by making the rule strict, it prevents the machine having to check every single code-path (which becomes a "halting problem").

Understanding 'using' keyword : C++

Can someone please explain below output:
#include <iostream>
using namespace std;
namespace A{
int x=1;
int z=2;
}
namespace B{
int y=3;
int z=4;
}
void doSomethingWith(int i) throw()
{
cout << i ;
}
void sample() throw()
{
using namespace A;
using namespace B;
doSomethingWith(x);
doSomethingWith(y);
doSomethingWith(z);
}
int main ()
{
sample();
return 0;
}
Output:
$ g++ -Wall TestCPP.cpp -o TestCPP
TestCPP.cpp: In function `void sample()':
TestCPP.cpp:26: error: `z' undeclared (first use this function)
TestCPP.cpp:26: error: (Each undeclared identifier is reported only once for each function it appears in.)
I have another error:
error: reference to 'z' is ambiguous
Which is pretty clear for me: z exists in both namespaces, and compiler don't know, which one should be used. Do you know? Resolve it by specifying namespace, for example:
doSomethingWith(A::z);
using keyword is used to
shortcut the names so you do not need to type things like std::cout
to typedef with templates(c++11), i.e. template<typename T> using VT = std::vector<T>;
In your situation, namespace is used to prevent name pollution, which means two functions/variables accidently shared the same name. If you use the two using together, this will led to ambiguous z. My g++ 4.8.1 reported the error:
abc.cpp: In function ‘void sample()’:
abc.cpp:26:21: error: reference to ‘z’ is ambiguous
doSomethingWith(z);
^
abc.cpp:12:5: note: candidates are: int B::z
int z=4;
^
abc.cpp:7:5: note: int A::z
int z=2;
^
which is expected. I am unsure which gnu compiler you are using, but this is an predictable error.
You get a suboptimal message. A better implementation would still flag error, but say 'z is ambiguous' as that is the problem rather than 'undeclared'.
At the point name z hits multiple things: A::z and B::z, and the rule is that the implementation must not just pick one of them. You must use qualification to resolve the issue.

Using clang 3.1 with initializer lists

When I compile this code:
template<typename T>
struct S {
std::vector<T> v;
S(initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
};
using the following command line:
clang++ -std=c++11 -stdlib=libc++ initializer_list.cpp
I get the following error.
initializer_list.cpp:12:23: error: expected ')'
S(initializer_list<T> l) : v(l) {
Does anyone know the fix if any??
Thanks in advance
You probably meant to write std::initializer_list<T>. Make sure you include <initializer_list>.
Your code sample is incomplete. It would be useful if you can provide a complete example. The problem with the code as written is that you're missing
#include <initializer_list>
#include <vector>
#include <iostream>
... and initializer_list is in namespace std, so you're also missing a std:: from your constructor declaration.
However, since you've claimed that neither of these is the issue, the most likely cause would seem to be that your C++ standard library implementation doesn't provide std::initializer_list. That would be the case if Clang is using GCC's libstdc++, and you do not have a suitably new version of that installed: you need at least version 4.4, but note that a patch is required to fix bugs in libstdc++-4.4 in order to make it work with Clang in C++11 mode, otherwise you will get errors about type_info and various other problems.
Also, you say that the diagnostic you received is this:
initializer_list.cpp:12:23: error: expected ')'
S(initializer_list<T> l) : v(l) {
^
(I've reconstructed the caret from the provided column number; it would be useful to preserve it in future questions.) For any of the above explanations, this will not be the first diagnostic which Clang produces; that would be something along the lines of:
initializer_list.cpp:12:5: error: no template named 'initializer_list'; did you mean 'std::initializer_list'?
S(initializer_list<T> l) : v(l) {
^~~~~~~~~~~~~~~~
std::initializer_list
So either you've missed out the first diagnostic from your question, or the problem is that you have declared some other (non-template) type named initializer_list in the code you omitted in your question, and that is hiding std::initializer_list. Without seeing the rest of your code or the rest of your diagnostics, it's not possible to tell which.