I've got some code originating from a DSL that needs to be translated for a C++ caller. I need to figure out how to sort #include dependencies in C++. Fortunately, I have a few restrictions that can make my task easier:
- The result contains no templates or macros. I can use templates or macros to make my life easier, but the DSL doesn't explicitly generate anything that requires them- a开发者_开发百科ll preprocessing, code generation is taken care of on that end.
- The resulting code doesn't have to be readable or maintainable at all- it's going to be both produced and consumed by a program. Preferably it would not involve any performance penalties or confuse the optimizers, but I can live if it has to.
However, I have to convert some code that describes programs that are legal C++, but can never be defined, such as
struct X {
Y y;
Y func();
};
struct Y {
X func();
};
// or
struct Y {
void func(X x);
};
struct X {
void func(Y y);
};
So far, I came up with the idea that I would make each type it's own independent header, and then in the implementation file, I can just #include all the types the implementation depends on, which is not going to be too difficult. The issue is how I can mangle the code of X and Y so that this is possible.
Right now, I've thought of applying RVO and NRVO, and doing something somewhat similar for arguments. But, aren't there cases where they're not just not really optimizations, but not actually possible? This is written in MSVC10 so I can cope with any additional features C++0x has to offer here.
Edit: I edited my code, because I slightly understated my needs. RVO and NRVO also can't cut this.
Edit edit: I guess that, if forward declarations will suffice for function return values and arguments, I could topologically sort for the include orders of data members. After all, it's still not legal to do something like
struct X {
Y y;
};
struct Y {
X x;
};
Topological sort is the way to go.
If that doesn't work, you need to transform your code using shared_ptr or something that relaxes the ordering constraints.
Why not use forward declarations?
Your example is perfectly ok if you declare X and Y this way:
struct Y;
struct X {
Y func();
};
struct Y {
X func();
};
You could put every type declaration into its own header, prepend it by forward declarations of every type used in the declaration and then in the implementation file include all headers of used types. If you forward-declare every type used in the type declaration you no longer need to worry about what file to include first. It doesn't matter.
To sum it up:
headerA.h
#pragma once
class B;
class A {
B b;
public:
void myfunc();
};
headerB.h
#pragma once
class A;
class B {
A a;
};
implA.cpp
#include "headerA.h"
#include "headerB.h"
void A::myfunc() {
// ...
}
This way when using type A in unrelated code, you have to include both headerA.h
and headerB.h
. If you just want to include headerA.h
when you use type A, adjust the headers this way:
headerA.h
#pragma once
class B;
#include "headerB.h"
class A {
B b;
public:
void myfunc();
};
headerB.h
#pragma once
class A;
#include "headerA.h"
class B {
A a;
};
The inclusion guards will take care of the rest.
pass arguments by address, or create an intermediate data-type which is not dependent on either X or Y and pass that. you really can't avoid return/pass by value issues because the size/interfaces are not available. as is, they are co-dependent.
i suppose another option would be to declare them both in the same class interface.
you could use templates and specializations... but that will likely be messy to maintain unless you're willing to write the definitions, and the generator provides an option for this.
精彩评论