So I have this c++ code which I have written for c++0X. It used to compile in MSVC 2012, but now I switched to MingW64 4.8.1 because I was dissatisfied with the lack of C++11 support in MSVC. The following is part of some code which implements a simple Entity/Component System.
This is the error I get:
if(e->components.find(T::ID) == e->components.end())
undefined reference to
`EL::Position3DComponent::ID' ELEntityManager.h /Elementium/Elementium line
64 C/C++ Problem
which is related to using T::ID...
Here is some further explanation of what I used to use this code for in MSVC 2012:
In every component, I have a static const ELComponentID member which is initialized to the component's id. This is used because I need to easily get the entities which have a certain component, so I'm using a multimap in the ELEntityManager whose key is ELComponentID and whose value is a unique_ptr containing the ELEntity who has such a component.
In the ELEntity class, I use an unordered_map whose key is ELComponentID and whose value is a unique_ptr containing the ELComponent in question.
Yes it does take up a little more memory, but I do this mainly for access speed.
file ELEntityManager.h:
//Includes
#include <map>
#include <memory>
#include "ELEntity.h"
#include "ELComponent.h"
namespace EL{
class ELEntityManager
{
public:
//...
template<typename T> void addComponent(std::unique_ptr<ELEntity> e, std::unique_ptr<ELComponent> c)
{
if(c == nullptr || e == nullptr)
return;
if(e->components.find(T::ID) == e->components.end()) //***** <-- This is where I get the error.
{
//...
}
//...
}
//...
private:
//******************************************
// Private data members
//******************************************
std::multimap<ELComponentID, std::unique_ptr<ELEntity> > entities;
};
};// End namespace
file ELEntity.h:
//Includes
#include <unordered_map>
#include <memory>
#include "ELComponent.h"
namespace EL{
class ELEntity
{
friend class ELEntityManager;
//...
private:
//******************************************
// Private data members
//******************************************
/**The map of ComponentIDs with their components.*/
std::unordered_map<ELComponentID, std::unique_ptr<ELComponent> > components;
};
};// End namespace
file ELComponent.h:
//Includes
#include <unordered_map>
#include <functional>
#include <string>
#include <vector>
#include "ELMath.h"
namespace EL{
/**
* Component IDs.
*/
enum ELComponentID {
LogicalDevice = 1, // Start the enum at 1.
Viewport,
Position3D,
Position2D,
Orientation,
PhysicsRK4
};
/**
* Base component class.
*/
struct ELComponent
{
};
/**
* Position3D component, derives from ELVector3D in EL::Math.
*/
struct Position3DComponent: public ELComponent, EL::Math::ELVector3D
{
static const ELComponentID ID = Position3D;
};
//...
then I have this in main.cpp as a test (with all the required includes, etc...):
EL::ELEntityManager em;
std::unique_ptr<EL::ELEntity> e(new EL::ELEntity());
std::unique_ptr<EL::Position3DComponent> obj(new EL::Position3DComponent());
obj->x = 1.0;
obj->y = 2.0;
obj->z = 3.0;
em.addComponent<EL::Position3DComponent>(std::move(e), std::move(obj));
Now my question is, am I doing something wrong which is gcc specific, is the T::ID not supported in gcc/mingw, or has anything changed in the final c++11 implementation which wasn't in for MSVC 2012?
How do I fix this error? If it can't be done anymore in c++11, or if there's a bug in gcc, can I do this any other way?
Thanks a lot in advance for your replies! :)
I think GCC is right. From the code you posted, it seems to me you are not providing a definition for your static data member.
Since you are passing T::ID in input to std::unordered_map::find(), which takes its argument by reference, you are odr-using ID (ODR stands for One Definition Rule, and odr-using means, in short, that the compiler needs to know the address of that object).
Since the address of the static data member is needed, but no definition at global namespace is provided, you end up with an unresolved symbol error from the linker.
Per paragraph 9.4.2/3 of the C++11 Standard:
If a non-volatile const static data member is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression
is a constant expression (5.19). [...] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.
Therefore, to solve the problem, just add a definition at namespace scope in a .cpp file (or in a header included by just one .cpp file):
const ELComponentID Position3DComponent::ID;
Related
I am a .Net C# programmer trying to program in C++. I have an application that uses a third party library. When i try and use an Enum from the library in a function for this library I get an error message of type not allowed:
I have included the library:
#include <Trading.h>
using namespace Trading;
Trading.h includes Enumerations.h that contains:
/// Returns string representation.
FOO std::string enumToString (TimeInForce::Enum);
/// Trading session event type.
struct FOO TradSesEvent
{
/// #copydoc TradSesEvent
enum Enum
{
...
};
};
Code of the Application.cpp simplified to the problem:
#include <Trading.h>
using namespace Trading;
class Application
{
public:
Application(const Settings& settings) : settings_(settings)
{
orderBook_.reset(new OrderBook());
...
}
private:
// Store of orders sent to counterparty.
PtrTraits<OrderBook>::UniquePtr orderBook_;
void onSendNewOrder(Order& newOrder)
{
//create unique_ptr to fill in the order values and sen
PtrTraits<Order>::UniquePtr order(new Order(orderBook_->newId()));
order->timeInForce = TimeInForce.Day;
...
}
};
Error message:
struct Application::TimeInForce type name is not allowedC/C++(254)
The syntax for naming a member of an unscoped enum declared in a class or namespace TimeInForce is:
TimeInForce::Day
The period (.) is used for accessing non-static members of classes.
I would like to split a class implementation into three parts, to avoid that users need to deal with the implementation details, e.g., the libaries that I use to implement the functionality:
impl.cpp
#include <api.h>
#include <impl.h>
Class::Class() {
init();
}
Class::init() {
myData = SomeLibrary::Type(42);
}
Class::doSomething() {
myData.doSomething();
}
impl.h
#include <somelibrary.h>
class Class {
public:
Class();
init();
doSomething();
private:
SomeLibary::Type myData;
}
api.h
class Class {
Class();
doSomething();
}
The problem is, that I am not allowed to redefine headers for the class definition. This does not work when I define Class() and doSomething() only in api.h, either.
A possible option is to define api.h and do not use it in the project at all, but install it (and do not install impl.h).
The obvious drawback is, that I need to make sure, that the common methods in api.h and impl.h always have the same signature, otherwise programs using the library will get linker errors, that I cannot predict when compiling the library.
But would this approach work at all, or will I get other problems (e.g. wrong pointers to class members or similar issues), because the obj file does not match the header?
The short answer is "No!"
The reason: any/all 'client' projects that need to use your Class class have to have the full declaration of that class, in order that the compiler can properly determine such things as offsets for member variables.
The use of private members is fine - client programs won't be able to change them - as is your current implementation, where only the briefest outlines of member functions are provided in the header, with all actual definitions in your (private) source file.
A possible way around this is to declare a pointer to a nested class in Class, where this nested class is simply declared in the shared header: class NestedClass and then you can do what you like with that nested class pointer in your implementation. You would generally make the nested class pointer a private member; also, as its definition is not given in the shared header, any attempt by a 'client' project to access that class (other than as a pointer) will be a compiler error.
Here's a possible code breakdown (maybe not error-free, yet, as it's a quick type-up):
// impl.h
struct MyInternal; // An 'opaque' structure - the definition is For Your Eyes Only
class Class {
public:
Class();
init();
doSomething();
private:
MyInternal* hidden; // CLient never needs to access this! Compiler error if attempted.
}
// impl.cpp
#include <api.h>
#include <impl.h>
struct MyInternal {
SomeLibrary::Type myData;
};
Class::Class() {
init();
}
Class::init() {
hidden = new MyInternal; // MUCH BETTER TO USE unique_ptr, or some other STL.
hidden->myData = SomeLibrary::Type(42);
}
Class::doSomething() {
hidden->myData.doSomething();
}
NOTE: As I hinted in a code comment, it would be better code to use std::unique_ptr<MyInternal> hidden. However, this would require you to give explicit definitions in your Class for the destructor, assignment operator and others (move operator? copy constructor?), as these will need access to the full definition of the MyInternal struct.
The private implementation (PIMPL) idiom can help you out here. It will probably result in 2 header and 2 source files instead of 2 and 1. Have a silly example I haven't actually tried to compile:
api.h
#pragma once
#include <memory>
struct foo_impl;
struct foo {
int do_something(int argument);
private:
std::unique_ptr<foo_impl> impl;
}
api.c
#include "api.h"
#include "impl.h"
int foo::do_something(int a) { return impl->do_something(); }
impl.h
#pragma once
#include <iostream>
struct foo_impl {
foo_impl();
~foo_impl();
int do_something(int);
int initialize_b();
private:
int b;
};
impl.c
#include <iostream>
foo_impl::foo_impl() : b(initialize_b()} { }
foo_impl::~foo_impl() = default;
int foo_impl::do_something(int a) { return a+b++; }
int foo_impl::initialize_b() { ... }
foo_impl can have whatever methods it needs, as foo's header (the API) is all the user will see. All the compiler needs to compile foo is the knowledge that there is a pointer as a data member so it can size foo correctly.
I'm getting this super bazar bug in my code that I can't figure out. Basically what's happening is the data member 'char_string' is being created without me even assigning anything to it. It prints out "test123", when in the process.cpp file, I haven't copied the data to it yet.
main.cpp
#include <iostream>
using namespace std;
#include "process.h"
int main(){
char string[] = "test123";
w1::CString test(string);
return 0;
}
process.h
#ifndef PROCESS_H
#define PROCESS_H
namespace w1{
class CString{
private:
int num_of_chars;
char char_string[];
public:
CString(char *);
};
}
#endif
process.cpp
#include <iostream>
#include "process.h"
w1::CString::CString(char * c_string){
std::cout << char_string << std::endl;
}
OUTPUT:
test123
It is not instantiated. According to http://www.cplusplus.com/doc/tutorial/classes/,
For members of fundamental types, it makes no difference which of the
ways above the constructor is defined, because they are not
initialized by default, but for member objects (those whose type is a
class), if they are not initialized after the colon, they are
default-constructed.
Pointers (and thus arrays) are fundamental types, so they are not default constructed if uninitialized. They will point to some memory location, and using that location will result in undefined behavior. In this case you are seeing it happen to point to an actual (and relevant) memory location, but it could just as easily point to 0 (nullptr) or any other value. You might need to look in the internals of your compiler to learn why, but in general you should never depend on such undefined behavior.
In my original code, I refer to the third-party .H in the ClassOne header file and everything works fine. Now, I received a new requirement that doesn't allow me to refer to the third-party .H in the ClassOne header file. So that the consumer of my code (i.e. ClassOne) will not have to indirectly includes the third-party .H file. I have tried the following modification but it doesn't work.
Here is the sample code:
// third_party.h
struct PPP
{
int x;
int y;
}; // without default constructor
// Original code!
//////////////////////////////////////////////
// ClassOne.h // my class
#include <third_party.h> // refer to the .H in header file
namespace X
{
class ClassOne
{
...
private:
boost::scoped_ptr<PPP> m_scpPPP;
};
}
// ClassOne.cpp
#include <third_party.h>
namespace X
{
ClassOne::ClassOne()
{
m_scpPPP.reset( new PPP() ); // fine
}
...
}
// Modified code!
==========================================================
// ClassOne.h
struct PPP; // error C2371: 'PPP' : redefinition; different basic types
namespace X
{
class ClassOne
{
...
private:
boost::scoped_ptr<PPP> m_scpPPP;
};
}
// ClassOne.cpp
#include <third_party.h>
namespace X
{
ClassOne::ClassOne()
{
m_scpPPP.reset( new PPP() ); // now see errors.
// error C2512: 'PPP' : no appropriate default constructor available
}
...
}
Question 1> Where should I forward declare the third-party struct type PPP?
Question 2> Why the compiler now complain about the PPP that has no default constructor?
It is not standard behavior to instantiate templates with incomplete types, therefore it shouldn't work boost::scoped_ptr.
Having said that, unique_ptr has a special rule, allowing to take incomplete types. If you use it (instead of boost::scoped_ptr), then it is done like this :
// forward declaration of PPP, assuming c++ header
struct PPP;
namespace X
{
class ClassOne
{
...
private:
std::unique_ptr<PPP> m_scpPPP;
};
}
Simply put: That won't work. Since you use PPP (and not PPP*) in side your ClassOne, the compiler needs to know the size at that point, so it needs to know the definition of PPP. To hide PPP from the public .h file, you'll have to do more. One possible solution is to hide your implementation class behind another class. Another would be only to refer to PPP* in your class declaration (although that would make the usage of scoped_ptr<> a bit pointless).
The compiler expects a default constructor because he assumes there is one. He needs the definition of the class to call "new" as well. You can work around this problem by moving the implementation of the ctor to the .cpp file, where you may include thirdParty.h.
So far I've looked up most of the typical solutions for cases of this error and yet non of them seems to work with my code. I'm using dev-c++
The structure of problematic class is following.
m.hh
#ifndef M_H
#define M_H
#include "z.hh"
#include <iostream>
#include <string>
using namespace std;
class M: public Z
{ /* this line is marked by the compiler as errorneous */
void m1();
void m2();
};
#endif
m.cpp
#include <iostream>
#include <string>
#include "m.hh"
using namespace std;
void M::m1() {/*bla bla*/};
void M::m2() {/*bla bla*/};
}
EDIT:
z.hh
#ifndef Z_H
#define Z_H
#include "m.hh"
#include <iostream>
#include <string>
using namespace std;
class Z;
static Z* s(string g, string i);
#endif
z.cpp
#include "z.hh"
#include <iostream>
#include <string>
class Z
{
public:
string i;
string g;
void set_i(string im) {i = im;}
string get_i() {return i;}
string get_g() {return g;}
virtual void m1()=0;
virtual void m2()=0;
Z* s(string g, string i) {
Z * z;
if(g=="m"){
M * z = new M;
}
}
};
Thanks!
Remove #include "m.hh" from z.hh to fix the circular include.
THE PROBLEM
You cannot derive from an incomplete type, which is what Z is in m.hh.
Upon deriving from a type the compiler must know the definition of said type. Just imagine you are trying to call a derived member function from Z on an object of type M, how would the compiler know if such call is a valid construct without knowing if Z actually declares such member?
And, a more relevant point, how would M be able to initialize Z without knowing what Z is?
THE SOLUTION
Move the definition of class Z to z.hh, and leave the definitions of its member functions in z.cpp (the same way you have split up M across m.hh, and m.cpp).
Well, the z.cpp file is actually a class declaration and should be a header file. A forward decalaration is only sufficient when you deal with pointers to that class, but not for inheriting from one (the compiler does need to know z's class layout for that).
The z.hh is not really needed, and the function declaration in it is not what you think (it's not a member function declaration). You can delete it and rename z.cpp to z.hh.
Ok, the exchange with #Luchian Grigore made me realize what you probably wanted and why you had "two z.hh". Z is to produce an M, but M inherits from Z, so there is a circular dependency. In C/C++ the way to break such a circle is to limit what one of the classes needs to know from the other: In order to declare a member function s that produces a pointer to a new M Z's class declaration only needs a typename M, not a the whole class declaration. So just a forward declaration (class M;) that introduces the type name M into the declaration of Z is enough; if the pointer to the M object is returned as a pointer to the base, Z, M's name is not even needed at all when Z is declared.
The definition of the factory function (be it file static or a member function) needs, if it is to produce an M, M's complete declaration though. That would be in a seaparate cpp file, which would include a complete header with M's full declaration.