The following program
#include <ctime>
struct clock {};
int main() {
clock c;
}
fails to compile on both g++ 5.4 and clang 3.8 (Ubuntu 64-bit).
g++ output
clock.cpp: In function ‘int main()’:
clock.cpp:6:11: error: expected ‘;’ before ‘c’
clock c;
^
clang output
clock.cpp:6:5: error: must use 'struct' tag to refer to type 'clock' in this scope
clock c;
^
struct
/usr/include/time.h:189:16: note: struct 'clock' is hidden by a non-type declaration of 'clock' here
extern clock_t clock (void) __THROW;
^
1 error generated.
The diagnostics vary a little in form, but are related to the same issue. There is a clash with the standard C function clock and the struct of the same name defined in the program. The relevant declaration from time.h:
extern clock_t clock (void) __THROW;
The question is: shouldn't such symbols be in the std namespace, since the program includes <ctime>? Interestingly, that very declaration sits a couple of lines after a macro which reads __BEGIN_NAMESPACE_STD. In addition, in <ctime>, one can see:
namespace std
{
using ::clock_t;
using ::time_t;
using ::tm;
using ::clock;
...
}
Is there some kind of bug here?
Thank you.
The question is: shouldn't such symbols be in the std namespace...
Yes, and they are. Unfortunately, the C++ standard also allows implementations to put names from C-library derived headers in the global namespace. In this case, you get std::clock and ::clock.
This applies to all the <c*> C++ headers with a corresponding <*.h> version in C.
Related
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.
Consider following program:
#include <cstdio>
#include <cmath>
int main()
{
int d = (int)(abs(0.6) + 0.5);
printf("%d", d);
return 0;
}
g++ 7.2.0 Output 0 ( See live demo here )
g++ 6.3.0 ( See live demo here )
prog.cc: In function 'int main()':
prog.cc:6:26: error: 'abs' was not declared in this scope
int d = (int)(abs(0.6) + 0.5);
^
prog.cc:6:26: note: suggested alternative:
In file included from prog.cc:2:0:
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/cmath:103:5: note: 'std::abs'
abs(_Tp __x)
^~~
clang++ 5.0.0 Output 1 ( See live demo here )
clang++ 3.6.0 ( See live demo here )
prog.cc:6:19: error: use of undeclared identifier 'abs'; did you mean 'fabs'?
int d = (int)(abs(0.6) + 0.5);
^~~
fabs
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:181:14: note: 'fabs' declared here
__MATHCALLX (fabs,, (_Mdouble_ __x), (__const__));
^
/usr/include/math.h:71:26: note: expanded from macro '__MATHCALLX'
__MATHDECLX (_Mdouble_,function,suffix, args, attrib)
^
/usr/include/math.h:73:22: note: expanded from macro '__MATHDECLX'
__MATHDECL_1(type, function,suffix, args) __attribute__ (attrib); \
^
/usr/include/math.h:76:31: note: expanded from macro '__MATHDECL_1'
extern type __MATH_PRECNAME(function,suffix) args __THROW
^
/usr/include/math.h:79:42: note: expanded from macro '__MATH_PRECNAME'
#define __MATH_PRECNAME(name,r) __CONCAT(name,r)
^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:88:23: note: expanded from macro '__CONCAT'
#define __CONCAT(x,y) x ## y
^
1 error generated.
Microsoft VC++ 19.00.23506 Output 1 ( See live demo here )
What exactly is happening here in this program ? Why it gives different output when compiled on different C++ compilers ? Why program exhibits different behavior even on different version of same compiler ? Is this compiler issue or standard library (libstdc++ & libc++) issue ? What C++ standard says about this ?
P.S: I know that I need to write std::abs instead of abs. But this is not my question.
All the cname library headers that bring in functionality from the C standard library must introduce those symbols in namespace std. They also may, but definitely not must introduce them into the global namesapce. [headers]/4:
Except as noted in Clauses [library] through [thread] and Annex
[depr], the contents of each header cname is the same as that of the
corresponding header name.h as specified in the C standard library. In
the C++ standard library, however, the declarations (except for names
which are defined as macros in C) are within namespace scope of the
namespace std. It is unspecified whether these names (including any
overloads added in Clauses [language.support] through [thread] and
Annex [depr]) are first declared within the global namespace scope and
are then injected into namespace std by explicit using-declarations.
So different compilers, and even different compiler versions, mean different implementation details.
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.
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.
For some reason, I cannot use uniform_int_distribution (from C++ TR1 header <tr1/random>) in Mingw-w64 G++, even though exponential_distribution works. The following is the relevant code:
#include <tr1/random>
using namespace std;
int main() {
tr1::random_device rd;
tr1::exponential_distribution<int> exprng(1);
tr1::uniform_int_distribution<> unirng(5, 500);
tr1::mt19937 rnd_gen(rd());
// ...
}
When I try to compile it, I get this:
> g++ -o foo.exe -std=c++11 foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:8:5: error: 'uniform_int_distribution' is not a member of 'std::tr1'
tr1::uniform_int_distribution<> unirng(5, 500)
^
foo.cpp:8:35: error: expected primary-expression before '>' token
tr1::uniform_int_distribution<> unirng(5, 500);
^
foo.cpp:8:50: error: 'unirng' was not declared in this scope
tr1::uniform_int_distribution<> unirng(5, 500);
^
I'm running the latest version of the compiler, 4.9.2. I've already tried removing using namespace std and changing the namespace prefix to std::tr1 and std. Any ideas?
Okay, I got the C++ TR1 and C++11 headers mixed up.
I was using C++ TR1 headers as a result of my misreading the GCC documentation, but it turns out uniform_int_distribution is part of C++11. C++11 and C++ TR1 aren't exactly source-compatible and minor adjustments are needed.
The corrected code is as follows:
#include <random>
using namespace std;
int main() {
random_device rd;
exponential_distribution<> exprng(1);
uniform_int_distribution<> unirng(5, 500);
mt19937 rnd_gen(rd());
// ...
}
(I'll cast the exponential_distribution output later in the program—the compiler told me that the template argument must be a floating-point type.)