I am starting a new project that will be targeting MSVC, GCC (latest), GCC 4.3 ARM and more. The waf build system we have built has C++11 feature detection of the compiler.
I now have preprocessor macros for all features in compiler that I am targeting for C++11, for example #ifdef WAF_FEATURE_CXX_STRONGLY_TYPED_ENUMS. I can therefore compile different code for what the compiler supports. As GCC nearly supports it all be MSVC isn't even close (even with MSVC 11)
This got me thinking about web development polyfills - if the feature isn't available implement it with the feature set available.
This is no way near as simple as web development polyfills as for C++11 but is there anything that I can simply implement with C++03 if the compiler doesn't support it?
This boils down to the fact that I want to use strongly typed enumerators in my public API but the scoping MyClass::MyEnumerator::EnumValue will look more like MyClass::EnumValue in C++03. Is there anyway I can get the same to occur in C++03 easily:
class MyClass {
public:
#ifdef WAF_FEATURE_CXX_STRONGLY_TYPED_ENUMS
enum class MyEnumerator : unsigned int {
#else
enum MyEnumerator {
#endif
EnumValue = 0
}
void method(MyEnumerator e);
}
MyClass mc = new MyClass();
mc.method(MyClass::MyEnumerator::EnumValue) // C++11
mc.method(MyClass::EnumValue) // C++03 :(
This is what you'll need to do (I made other trivial fixes about pointers and non-pointer access).
Bsically, it's what #demi said. I had to make a dummy enum name. This works in g++-4.7.
class MyClass {
public:
#if __cplusplus > 201000
enum class MyEnumerator : unsigned int {
EnumValue = 0
};
void method(MyEnumerator e) {}
#else
class MyEnumerator {
public:
enum Dummy {
EnumValue = 0
};
};
void method(MyEnumerator::Dummy e) {}
#endif
};
int main() {
MyClass mc;
mc.method(MyClass::MyEnumerator::EnumValue); // C++11 or C++03
}
You may emulate enum class as class. Your boilerplate code will be only in definition, but usage will be same for C++11 and C++03, and may be done with templates/macros. Look answer here
Related
I use TBB at multiple places in my project. But it seems that since I update Visual Studio from 15.6.X (X beeing the latest version) to 15.7.1 I get a compiler error at several places, telling me
[...]tbb\task_group.h(94): error C2530: 'my_task': references must be initialized
Looking at the referenced code (tbb/task_group.h):
//! Base class for types that should not be assigned.
class no_assign {
// Deny assignment
void operator=( const no_assign& );
public:
#if __GNUC__
//! Explicitly define default construction, because otherwise gcc issues gratuitous warning.
no_assign() {}
#endif /* __GNUC__ */
};
//! Base class for types that should not be copied or assigned.
class no_copy: no_assign {
//! Deny copy construction
no_copy( const no_copy& );
public:
//! Allow default construction
no_copy() {}
};
// ...
class ref_count_guard : internal::no_copy {
task& my_task; // compiler error occurs here
public:
ref_count_guard( task& t ) : my_task(t) {
my_task.increment_ref_count();
}
~ref_count_guard() {
my_task.decrement_ref_count();
}
};
I don't see why the compiler is complaining there, as the reference is initialized by the constructor. Finding the problem in my code is also not that easy, because the compiler error occurs in every single source file that uses TBB and I don't think I changed anything since my last successful compilation (besides updating VS).
One possibility that comes to my mind is related to this question. If msvc somehow inherits the base class constructors by default, a default constructor would be inherited explaining the error. But testing this scenario seems to disprove it (as the code compiles).
Why is msvc complaining here?
Update
This minimal example reproduces the error on my system:
#include <vector>
#include <tbb/tbb.h>
#include <tbb/flow_graph.h>
void main()
{
std::vector<int> src{1, 2, 3, 4, 5};
tbb::parallel_for_each(src.begin(), src.end(), [](int) { });
}
Update 2
Looks like just including tbb/tbb.h causes the error to occur. I don't even need to call anything. Rebuilding tbb with the new compiler version didn't help either.
Edit
Cross issue on github.
Simply removing /permissive- (e.g. set Comformance Mode to No in the C/C++ options) gets past this issue. I presume Intel will fix this soon.
This is a compiler bug when /permissive- option is used. It can be reproduced with the following code:
struct U {
template<typename T>
void foo() {
class A {
int& iref;
public:
A(int& ir) : iref(ir) { }
};
int the_answer = 42;
A a(the_answer);
}
};
int main() {
U u;
u.foo<int>();
return 0;
}
The code is perfectly valid, compliant C++. As you can see, the reference is explicitly initialized in the member initializer list of the constructor. Also this is seemingly a regression in VS, because at least the initial release of VS 2017 (15.0.something) compiles this code with /permissive-.
Below is the complete code to my project (no code has been omitted):
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
typedef enum{
MAJOR_BUTTON_IGNORED_FIRST = 0,
MAJOR_BUTTON_BLOCKS,
MAJOR_BUTTON_IGNORED_LAST,
}MAJOR_BUTTON_TYPE;
typedef enum{
BLOCK_IGNORED_FIRST = 0,
BLOCK_ORDINARY_SMASHABLE,
BLOCK_IGNORED_LAST,
}THING_TYPE;
class Datar{
private:
public:
MAJOR_BUTTON_TYPE majorType;
std::string majorButtonString;
std::vector<THING_TYPE>thingTypes;
std::unordered_map<THING_TYPE, std::string>thing2String;
Datar(){
}
virtual ~Datar(){};
virtual void initDatar(){};
};
class DatarBlock : public Datar{
private:
public:
virtual void initDatar(){
majorType = MAJOR_BUTTON_BLOCKS;
majorButtonString = "MajorButtonNames::blocks";
}
};
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
DatarBlock* db = new DatarBlock();
Datar* blah = static_cast<Datar*>(db); //Compiler error here ****
return 0;
}
At the line marked, there is a compiler error which says:
main.cpp:62:19: Static_cast from 'DatarBlock *' to 'Datar *', which
are not related by inheritance, is not allowed
Why does the compiler report it as an error ?
EDIT:I am using Xcode 7.2 (LLVM 7.0) , C++ Standard Library = libc++ (LLVM standard library with C++11 support), C++ Language Dialect = GNU++11
This code is invalid in C++11 as published (without DR 2148), where std::hash is not specialized for enum types (for an overview, see http://en.cppreference.com/w/cpp/utility/hash). It was accepted through libstdc++ 4.6 however (I do not have version numbers for libc++).
C++14 gains the desired specializations, but they are not implemented as of libstdc++ 5. They are implemented in libstdc++ 6, see GCC bug 60970 and DR 2148, and intentionally is available in C++11 mode as well. Whatever version of libc++ I am using does support them in C++14 mode only.
This is an example of why you need to look at all errors, in order, since earlier errors may render later errors completely meaningless.
I encountered different brace breaking behavior in clang-format for structs and classes.
The following example file illustrates it:
test.cpp
class TestClass
{
int member;
};
struct TestStruct
{
int member;
};
Running clang-format v3.7.0 with BreakBeforeBraces: Linux yields:
$ clang-format test.cpp -style="{BreakBeforeBraces: Linux}"
class TestClass
{
int member;
};
struct TestStruct {
int member;
};
However, clang-format v3.5.0 results in:
class TestClass
{
int member;
};
struct TestStruct
{
int member;
};
Is this intended behavior? I did not find any hint in the changelogs.
How could I fix this?
This seems to be intended behavior, since it is still there almost 5 years later, in clang-format version 10.0.0.
However, starting with version 3.8.0, you can fine-tune the BreakBeforeBraces behavior by setting BreakBeforeBraces: Custom. When you do this, you can then set the BraceWrapping flags. In particular, there are separate flags AfterClass and AfterStruct - if you set both of these to true you should get back the behavior you had with version 3.5.0. See the documentation for details on this.
The following code will compile as C, but not as C++:
#include <stdio.h>
struct somestruct {
int id;
enum {
STATE1 = 0,
STATE2,
STATE3,
STATE4,
} state;
};
int main(int argc, char *argv[])
{
static struct somestruct s;
if (s.state == STATE1) {
printf("state1\n");
}
return 0;
}
In C++, I would have to use somestruct::STATE1 (because the enum declaration is restricted to the struct/class?).
The project I'm working on is to be written in C, but currently we use some C++ libraries (Arduino), so we're compiling our c-code with a C++ compiler. So is there any way to make the above code compile in C++?
You could code it in a form that is compatible with both languages, such as:
typedef enum
{
STATE1 = 0,
STATE2,
STATE3,
STATE4,
} eState ;
struct somestruct
{
int id ;
eState state ;
};
Alternatively if you really cannot change the struct and enum definition then the following is portable (if ugly), and requires that you change every reference to the enum rather then the single definition (i.e. it has little merit IMO):
#if defined __cplusplus
#define SOMESTRUCT(e) somestruct:: e
#else
#define SOMESTRUCT(e) e
#endif
Then:
...
if (s.state == SOMESTRUCT(STATE1)) {
...
Use a using statement to bring the identifier into the calling scope:
struct somestruct {
int id;
enum {
STATE1 = 0,
STATE2,
STATE3,
STATE4,
} state;
};
#ifdef __cplusplus
using somestruct::STATE1; // <-- here
#endif
In C++, yes, exactly as you said: refer to it as somestruct::STATE1.
I don't see how you're going to be able to make this portable across both languages, but then again I don't see why you need to. Write somestruct::STATE1 in the C++ code, and STATE1 in the C code. Use macros if you really need to flip between them without duplicating code.
Don't forget to fix your broken expression s->state; s is not a pointer.
You could use a c macro definition
#define STATE1 somestruct::STATE1
That Should Allow To Go STATE1
I Would Recommend Against it since you are using a c++ compiler so you might as well make use of the c++ features that it gives you and just put somestruct::STATE1.
The following works just-fine in MSVC2008 and MSVC2010:
class Foo {
public:
static void FuncA(void) {
FuncB(); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008
}
static void FuncB(void);
};
Yes, this is kinda weird: FuncA() calls FuncB(), even though (at that point) FuncB() is not-yet-declared. However, MSVC2008 and MSVC2010 thinks this is fine.
Apparently, gcc doesn't think this is fine -- FuncB was not declared in this scope.
ISSUE: I have a bunch of these, and it would be a "pain" to declare them, and later define them. Further, it would be hard to "order" them properly so each only calls functions after those were declared. But, I'm guessing I need to declare-first-then-define-later?
Are the rules different for whether these functions are template-or-not, or defined within a template-class or not?
Specifically, I've noticed Microsoft is very "late-compiling" where it accepts tons of inter-coupled code, and LATER resolves (at compile, when the template-parameterization is triggered), while gcc seems to want to compile now when it "sees" the code (an initial pass for correctness, and again during parameterization/invocation).
(This problem shows up as we port our Microsoft code to Linux/gcc.)
===UPDATE===
The following are "alternate" scenarios that we have (in this code-porting effort), and would your answer change based on any of these?
// Alternate-Scenario-B
class Foo2 {
public:
template<typename SOME_TYPE>
static void FuncA(const SOME_TYPE& some_type) {
FuncB(some_type); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008
}
template<typename SOME_TYPE>
static void FuncB(const SOME_TYPE& some_type);
};
...and:
// Alternate-Scenario-C
template<typename SOME_TYPE>
class Foo3 {
public:
static void FuncA(const SOME_TYPE& some_type) {
FuncB(some_type); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008
}
static void FuncB(const SOME_TYPE& some_type);
};
===UPDATE+2===
Thanks for the comments, where consensus seems that this is valid C++ code, and should work (as #Adam suggested, a function "defined-inline" should behave as if it were defined after the class, and should be able to call functions defined in the class interface after that inline definition).
MORE INFORMATION:
Yes, I really have this compile error from the first example in the FuncA() inline implementation:
'FuncB' is not a member of 'Foo'
...using:
gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
(Recall that this works on MSVC2008/MSVC2010).
I realize now that my code-example (above) is insufficient (the above example does not show this error on gcc), here are some more details:
Foo has a base-class (I don't think that should matter)
Foo defines an internal enum which is passed through these funcs (I don't think this matters)
these functions are "expanded" through a macro (I think significant -- see below)
there are fifty-six (56) of these functions (I think significant -- see below)
A more complete code example would be (and I am not proud of this):
#define FOO_FUNCS(CLASS_NAME,CLASS_ENUM) \
static void FuncA(CLASS_ENUM value_enum) { \
FuncB(value_enum); /*PROBLEM*/ \
} \
static void FuncB(CLASS_ENUM value_enum) { \
FuncC(value_enum); \
} \
/*...THERE ARE 56 FUNCS IN THIS MACRO, THREE LINES EACH...*/
class Foo : public FooParent {
public:
enum FooEnum { FOO_ONE, FOO_TWO };
FOO_FUNCS(Foo,FooEnum) // EXPAND THE 56 FUNCS
};
CODE INTENT: The FooParent base class has implementation that is intended to be "shared" by (many) derived classes. The derived classes define their own enum values. Functions that used these enum values were implemented through a macro (because the FooParent is not a template<>, and cannot rely upon the derived-enum).
Curious behavior:
If the FooA(){FooB();} nesting references a function defined "later" by only a "few-lines", then gcc compiles fine. However, if the yet-to-be-declared function is much later, like Foo2(){Foo53();}, then gcc concludes that Foo53() is not a member of the class (but it is).
Here's what I think is going on:
There seems to be an issue with lots-of-code (for 56 functions) that are physically on "one-line". If I take these functions out of the macro, AND if I remove \ escape-line-endings, then gcc compiles fine.
Thus, I think the (code-porting) answer is:
don't use a preprocessor-macro
make a FooParentBase<> template class derived from FooParent, from which we derive Foo, which requires the typename Foo::enum as a template-parameter
I'm fine with these changes (I didn't like the macro), but I find it weird that gcc seems to have an issue here.
Are there other suggestions for how to fix this? (Is the above re-factoring what you would do?)
All three of your scenarios are correct and compile with both g++ and clang.
Your code looks perfectly legal to me. Inline definitions within a class definition are supposed to be treated equivalent to declarations with an inline definition immediately following the class definition (by which time the declaration of FuncB() would be available).
My version of GCC accepts this code as valid (all three examples you post, assuming I provide trivial implementations of each FuncB(), of course).
~$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
...
I believe more information is needed here. Perhaps post your version of GCC and the specific error message you're seeing.
========REPLY TO LATER UPDATE=======
I've tried your latest example with 70 functions in the macro, and it's still working for me in gcc 4.6.3. Here is the test I tried (with the macro shortened in the obvious way):
#include <iostream>
using std::cout;
struct FooParent {
static void Func71( int ) {
cout << "Called\n";
}
};
#define FOO_FUNCS(CLASS_NAME,CLASS_ENUM) \
static void Func1(CLASS_ENUM value_enum) { \
Func2(value_enum); /PROBLEM/ \
} \
static void Func2(CLASS_ENUM value_enum) { \
Func3(value_enum); \
} \
/* Functions Func3...Func69 snipped */ \
static void Func70(CLASS_ENUM value_enum) { \
Func71(value_enum); \
} \
/...THERE ARE 70 FUNCS IN THIS MACRO, THREE LINES EACH.../
class Foo : public FooParent {
public:
enum FooEnum { FOO_ONE, FOO_TWO };
FOO_FUNCS(Foo,FooEnum) // EXPAND THE 70 FUNCS
};
int main() {
Foo::Func1(Foo::FOO_ONE);
}