C++11 自动排序#在C+中包含依赖项+; 我有一些代码源于一个DSL,需要为C++调用方翻译。我需要知道如何在C++中对包含依赖项进行排序。幸运的是,我有一些限制可以使我的任务更容易: 结果不包含模板或宏。我可以使用模板或宏来简化我的生活,但是DSL并没有显式地生成任何需要它们的东西——所有的预处理、代码生成都是在这方面完成的 生成的代码根本不需要可读或可维护——它将由程序生成和使用。最好它不会涉及任何性能惩罚或混淆优化器,但如果必须的话,我可以活下去 但是,我必须转换一些描述合法C++程序但不能被定义的代码,例如 struct X { Y y; Y func(); }; struct Y { X func(); }; // or struct Y { void func(X x); }; struct X { void func(Y y); };

C++11 自动排序#在C+中包含依赖项+; 我有一些代码源于一个DSL,需要为C++调用方翻译。我需要知道如何在C++中对包含依赖项进行排序。幸运的是,我有一些限制可以使我的任务更容易: 结果不包含模板或宏。我可以使用模板或宏来简化我的生活,但是DSL并没有显式地生成任何需要它们的东西——所有的预处理、代码生成都是在这方面完成的 生成的代码根本不需要可读或可维护——它将由程序生成和使用。最好它不会涉及任何性能惩罚或混淆优化器,但如果必须的话,我可以活下去 但是,我必须转换一些描述合法C++程序但不能被定义的代码,例如 struct X { Y y; Y func(); }; struct Y { X func(); }; // or struct Y { void func(X x); }; struct X { void func(Y y); };,c++11,C++11,到目前为止,我想到了一个想法,我会让每种类型都有自己的独立头,然后在实现文件中,我可以#包括实现所依赖的所有类型,这不会太困难。问题是我怎样才能把X和Y的代码弄乱,这样才有可能 现在,我考虑应用RVO和NRVO,并对参数做一些类似的操作。但是,在有些情况下,它们不仅不是真正的优化,而且实际上是不可能的吗?这是用MSVC10编写的,因此我可以处理C++0x在这里提供的任何附加功能 编辑:我编辑了我的代码,因为我稍微低估了我的需求。RVO和NRVO也不能解决这个问题 编辑:我想,如果前向声明能够满足

到目前为止,我想到了一个想法,我会让每种类型都有自己的独立头,然后在实现文件中,我可以#包括实现所依赖的所有类型,这不会太困难。问题是我怎样才能把X和Y的代码弄乱,这样才有可能

现在,我考虑应用RVO和NRVO,并对参数做一些类似的操作。但是,在有些情况下,它们不仅不是真正的优化,而且实际上是不可能的吗?这是用MSVC10编写的,因此我可以处理C++0x在这里提供的任何附加功能

编辑:我编辑了我的代码,因为我稍微低估了我的需求。RVO和NRVO也不能解决这个问题

编辑:我想,如果前向声明能够满足函数返回值和参数的要求,我可以对数据成员的include顺序进行拓扑排序。毕竟,像这样做仍然是不合法的

struct X {
    Y y;
};
struct Y {
    X x;
};

为什么不使用转发声明

如果您这样声明X和Y,那么您的示例是完全正确的:

struct Y;
struct X {
    Y func();
};
struct Y {
    X func();
};
您可以将每个类型声明放在它自己的头中,通过转发声明中使用的每个类型的声明,然后在实现文件中包含所使用类型的所有头来预先结束它。如果转发声明类型声明中使用的每个类型,则无需再担心首先包含哪个文件。没关系

总而言之:

headerA.h

#pragma once
class B;

class A {
    B b;
public:
    void myfunc();
};
#pragma once
class B;
#include "headerB.h"

class A {
    B b;
public:
    void myfunc();
};
headerB.h

#pragma once
class A;

class B {
    A a;
};
#pragma once
class A;
#include "headerA.h"

class B {
    A a;
};
implA.cpp

#include "headerA.h"
#include "headerB.h"

void A::myfunc() {
    // ...
}
这样,在不相关的代码中使用类型A时,必须同时包含
headerA.h
headerB.h
。如果在使用类型A时只想包括
headerA.h
,请按以下方式调整标题:

struct Y;
struct X {
    Y func();
};
struct Y {
    X func();
};
headerA.h

#pragma once
class B;

class A {
    B b;
public:
    void myfunc();
};
#pragma once
class B;
#include "headerB.h"

class A {
    B b;
public:
    void myfunc();
};
headerB.h

#pragma once
class A;

class B {
    A a;
};
#pragma once
class A;
#include "headerA.h"

class B {
    A a;
};

包含保护将处理其余部分。

按地址传递参数,或创建一个不依赖于X或Y的中间数据类型并传递该类型。您确实无法避免返回/传递值问题,因为大小/接口不可用。事实上,它们是相互依存的

我想另一个选择是在同一个类接口中声明它们


您可以使用模板和专门化。。。但是,除非您愿意编写定义,否则维护起来可能会很麻烦,生成器为此提供了一个选项。

拓扑排序是一种方法


如果这不起作用,您需要使用shared_ptr或放松排序约束的东西来转换代码。

错误C2079:'X::y'使用未定义的结构'y'。不能将不完整类型当作完全定义的类型来使用,因为它们不是。您建议的两个头都会出错。@DeadMG好的,我应该提到使用这些类型的内联代码不会工作,因为编译器会这么说。如果头文件中确实有一些函数体,则必须包含所用类型的完整声明,或者将这些函数体移动到cpp文件中。@DeadMG还。。。在某些代码中使用类型A时,显然必须同时包含headerA.h和headedB.h。@Fiktik:什么,你是说“某些代码”,比如类定义?所以基本上,我所有的代码?@DeadMG我指的是实际使用定义类型的代码。我希望编辑后的答案在这一点上更加清晰。实际上,只通过值传递名称已知的类的代码是可以接受的。这是因为调用者和被调用者需要定义,因此调用定义良好,但“局外人”不需要定义,因此可以安全地忽略此类函数。