gcc warning "does not declare anything - c++

I'm working on updating some C++ code to C+11 by converting typedef's into using aliases. Given the following SCCE:
#include <iostream>
#include <linux/cn_proc.h>
/**
* Legacy C structure
*/
struct sample {
enum what {
FOO,
BAR
} what;
};
void tdef( ) {
typedef enum sample::what demo;
demo a = sample::FOO;
std::cout << a << std::endl;
}
void usingdemo( ) {
using demo = enum sample::what;
demo a = sample::BAR;
std::cout << a
<< std::endl;
}
int main() {
tdef();
usingdemo();
}
I'm getting a warning using the using declaration:
warning: declaration ‘enum sample::what’ does not declare anything
using demo = enum sample::what;
^
although the code compiles and executes fine. Compiler is g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609 Does the fault lie in the compiler, or in me?
Thanks for the replies. In regards to the comments about the C struct:
The "S" is SCCE is small, so I posted the smallest struct that would
demonstrate the issue. The actual struct I'm using is "struct proc_event" from
linux/cn_proc.h.
I'm just including it without the "extern C"
and it's working fine.

Does the fault lie in the compiler?
This is a compiler bug. It appears to have been reported already: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66159 . The problem reproduces when an elaborated name specifier is used in a using declaration. In this case, you need to use elaborated name specifier to avoid ambiguity with the member that has the same name.
Workaround: Use typedef declaration instead:
typedef enum sample::what demo;

The problem is that you have created both a type sample::what and a member sample::what. The compiler should, and apparently does resolve this and the warning is benign and apparently erroneous.
The problem goes away with:
struct sample {
enum what {
FOO,
BAR
} what_instance; // << Different identifier here
};
and:
using demo = sample::what;
Having a type identifier and an instance identifier with the same name is a bad idea in any case for a number of reasons. It is confusing to humans, and in this case the compiler also. Perhaps the compiler is trying to tell you something ;-)

You could simply define demo type to int because enum can be converted to a temporary int
void usingdemo( ) {
using demo = int;
...
}

Related

"Expected a type specifier" error when creating an object of a class inside another class declaration

I have a class called scratch and have used scratch.h to declare it.
Now I have another class called scratch2 under scratch2.h and want to create an object of scratch as a shared pointer.
This is the syntax I used inside scratch2 class declartion:
std::shared_ptr<scratch> newObject(new scratch());
But I am getting this error: Error: Expected type specifier
So I tried this instead:
std::shared_ptr<scratch> newObject2 = std::make_shared<scratch>();
which works fine. Can anyone please tell me why the first one isn't working?
My scratch.h code:
#ifndef _SCRATCH_
#define _SCRATCH_
#include <iostream>
class scratch {
private:
int _a;
float _b;
std::string _s;
public:
scratch();
scratch(int a, float b, std::string n);
~scratch();
};
#endif
and my scratch2.h:
#ifndef _SCRATCH_2_
#define _SCRATCH_2_
#include "scratch.h"
#include <memory>
class scratch2 {
std::shared_ptr<scratch> newObject(new scratch()); // Expected a type specifier error occurs here
std::shared_ptr<scratch> newObject2 = std::make_shared<scratch>(); // works fine here
};
#endif
Because in the context of declaring class members:
std::shared_ptr<scratch> newObject(new scratch());
This initially looks to the compiler as a class method declaration. C++'s syntax is very complicated. You can look at the entire declaration and understand what it's trying to do, but the compiler is parsing keywords one keyword at a time, and sees this:
type name( ...
inside a class declaration, and this starts to look like a class method declaration, and that's what the compiler tried to parse, and failed.
The formal specification of the C++ language spills a lot of ink on the subject of how things should be declared, mindful of the current state of compiler technology.
You need to work with the compiler, and use an alternate syntax that's unambiguous:
std::shared_ptr<scratch> newObject = std::shared_ptr<scratch>(new scratch());
Verified with gcc 5.3
Inside of a class definition, there are only two ways you're allowed to initialize your members. You can use = and you can use {}. You are not allowed to use ():
struct foo {
int x = 4; // OK
int y{7}; // OK
int z(12); // error
};
Admittedly, the compiler error in this case is extremely unhelpful.

Is this compile error typedef int (*j)() throw(A)?

#include <iostream>
class A {};
typedef int (*j)() throw(A);
int f()
{
std::cout << "function f" << std::endl;
return 0;
}
int main()
{
j y = f;
y();
}
In all sites and Stroustrup too says that there will be compile error, but it compiles.
Are there any changes in standard?
I know this is not an answer to this question -
MSVC 2010(that I have) throws no error, compiles fine and works without a hiccup
G++(GNU) says error: 'j' declared with an exception specification
Clang says error: exception specifications are not allowed in typedefs
Bottomline: Compiler bug in MSVC.
Exception specifications are not part of the type of a function. You can't overload on them, for example; and a pointer-to-function does not carry an exception specification. As #Aniket says, it's a Microsoft bug that their compiler accepts that declaration.

Error C2275 caused by template member function. Is this code wrong?

I think I've run into a (possible) VC6 (I know. It's what we use.) compiler error, but am open to the fact that I've just missed something dumb. Given the following code (It's just an example!):
#include <iostream>
// Class with template member function:
class SomeClass
{
public:
SomeClass() {};
template<class T>
T getItem()
{
return T();
};
};
// Dummy just used to recreate compiler error
class OtherClass
{
public:
OtherClass() {};
};
std::ostream& operator<<( std::ostream& oStr, const OtherClass& obj )
{
return oStr << "OtherClass!";
};
// Main illustrates the error:
int main(int argc, char* argv[])
{
SomeClass a;
OtherClass inst2 = a.getItem<OtherClass>(); // Error C2275 happens here!
std::cout << inst2 << std::endl;
return 0;
}
If I try to compile this code VC6, dies on a.getItem<OtherClass>() yielding:
Error C2275: 'OtherClass' : illegal use of this type as an expression.
Have I overlooked some trivial syntax issue? Am I breaking a rule?
This code compiles just fine under gcc 4.3.4. Is it yet another compliance issue with VC6?
Thanks!
Among many other things with the word template in it, VC6 couldn't deal with function templates where the template parameters aren't also function parameters. The common workaround was to add a dummy function parameter:
template<class T>
T getItem(T* /*dummy*/ = NULL)
{
return T();
} // note: no ; after function definitions
However, in general, VC6 is pretty lame and often chokes as soon as a TU contains the template keyword. I had to beat my head against it for several years (big code base compiled with several compilers/compiler versions; VC6 giving us an endless amount of trouble) and was very glad when I got rid of it in 2003.
This is likely to be a VC6 issue. Although VC6 compiles most basic templates correctly it is known to have many issues when you start to move towards the more advanced template uses. Member templates are an area where VC6 is known to be weak on conformance.
I believe that's another bug in VC6, you should really switch to a more up-to-date compiler.

c++ template seems to break access specifiers

The following code doesn't compile for obvious reasons, namely that Foo is trying to access a private member of Bar. However if you uncomment/comment the lines marked, making Foo a template, it does compile and outputs 42. What am I missing here? Why does this work? Seems to me it shouldn't.
Thanks for your help.
#include <iostream>
class Bar {
private:
static const int x = 42;
};
//template <int> // uncomment me
struct Foo {
static const int i = Bar::x;
};
int main(int argc, char* argv[]) {
std::cout << Foo::i << std::endl; // comment me
//std::cout << Foo<0>::i << std::endl; // uncomment me
}
If you are seeing this behavior, it is a compiler bug.
Both Comeau Online and Visual C++ 2010 reject the code as invalid because Bar::x is inaccessible. g++ 4.1.2 incorrectly accepts the invalid code (someone would need to test with a later version to see if it's been fixed; that's the only version I have on this laptop).
This seems like GCC bug 40843. It is listed as UNCONFIRMED, but I can reproduce it on g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3 as well.
VisualStudio 2010 said "error C2248: 'Bar::x' [...]
As the plateform was not speciifed, I have assessed that the assumption is false almost on Windows VC9.

How to workaround gcc-3.4 bug (or maybe this is not a bug)?

Following code fails with a error message :
t.cpp: In function `void test()':
t.cpp:35: error: expected primary-expression before '>' token
t.cpp:35: error: expected primary-expression before ')' token
Now I don't see any issues with the code and it compiles with gcc-4.x and MSVC 2005 but not with gcc-3.4 (which is still quite popular on some platforms).
#include <string>
#include <iostream>
struct message {
message(std::string s) : s_(s) {}
template<typename CharType>
std::basic_string<CharType> str()
{
return std::basic_string<CharType>(s_.begin(),s_.end());
}
private:
std::string s_;
};
inline message translate(std::string const &s)
{
return message(s);
}
template<typename TheChar>
void test()
{
std::string s="text";
std::basic_string<TheChar> t1,t2,t3,t4,t5;
t1=translate(s).str<TheChar>(); // ok
char const *tmp=s.c_str();
t2=translate(tmp).str<TheChar>(); // ok
t3=message(s.c_str()).str<TheChar>(); // ok
t4=translate(s.c_str()).str<TheChar>(); // fails
t5=translate(s.c_str()).template str<TheChar>(); // ok
std::cout << t1 <<" " << t2 <<" " << t3 << " " << t4 << std::endl;
}
int main()
{
test<char>();
}
Is it possible to workaround it on the level of translate function and message class, or maybe my code is wrong, if so where?
Edit:
Bugs related to template-functions in GCC 3.4.6 says I need to use keyword template but should I?
Is this a bug? Do I have to write a template keyword? Because in all other cases I do not have to? And it is quite wired I do not have to write it when I use ".c_str()" member function.
Why gcc-4 not always an option
This program does not starts when compiled with gcc-4 under Cygwin
#include <iostream>
#include <locale>
class bar : public std::locale::facet {
public:
bar(size_t refs=0) : std::locale::facet(refs)
{
}
static std::locale::id id;
};
std::locale::id bar::id;
using namespace std;
int main()
{
std::locale l=std::locale(std::locale(),new bar());
std::cout << has_facet<bar>(l) << std::endl;
return 0;
}
And this code does not compiles with gcc-4.3 under OpenSolaris 2009- broken concepts checks...
#include <map>
struct tree {
std::map<int,tree> left,right;
};
As mentioned elsewhere, that seems to be a compiler bug. Fair enough; those exist. Here's what you do about those:
#if defined(__GNUC__) && __GNUC__ < 4
// Use erroneous syntax hack to work around a compiler bug.
t4=translate(s.c_str()).template str<TheChar>();
#else
t4=translate(s.c_str()).str<TheChar>();
#endif
GCC always defines __GNUC__ to the major compiler version number. If you need it, you also get __GNUC_MINOR__ and __GNUC_PATCHLEVEL__ for the y and z of the x.y.z version number.
This is a bug in the old compiler. Newer GCC's, from 4.0 to (the yet unreleased) 4.5, accept it, as they should. It is standard C++. (Intel and Comeau accept it also.)
Regarding cygwin and opensolaris, of course gcc-3.4 is not the only option: the newer versions (the released 4.4.3, or the unreleased 4.5 branch) work fine on these OS'es. For cygwin, it's part of the official distribution (see the gcc4* packages in the list). For opensolaris, you can compile it yourself (and instructions on how to do so can easily be found with Google).
I would try to use a different workaround, since adding the template disambiguator there is incorrect and will break if you move to a different compiler later on.
I don't know the real code, but passing a regular std::string seems to work (option 1: avoid converting to const char * just to create a temporary) or you could provide an overloaded translate that takes a const char* as argument (if the compiler does not complain there), depending on your requirements.