Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否可以将前向声明和常规声明合并到一个文件中,然后像使用';我们分开了?_C++_C_C Preprocessor - Fatal编程技术网

C++ 是否可以将前向声明和常规声明合并到一个文件中,然后像使用';我们分开了?

C++ 是否可以将前向声明和常规声明合并到一个文件中,然后像使用';我们分开了?,c++,c,c-preprocessor,C++,C,C Preprocessor,我有一个疯狂的想法,通过执行一些宏欺骗,将前向声明头和实际的声明文件合并成一个。为了提供一些上下文,我对转发声明遵循的每日策略如下: 每个头文件都有其“_fwd.hpp”补码,其中包含该头文件中所有可向前声明实体的向前声明 我包括转发声明头,其中转发声明实际内容就足够了 我主要将常规声明头包含在.cpp文件中,并且仅当需要实际的实现信息时(需要实现大小、继承等) 但是,为每个集管配备单独的_fwd.hpp集管会污染项目,并且难以维护。因此,我提出了以下想法:将前向声明和实际声明合并到单个文件

我有一个疯狂的想法,通过执行一些宏欺骗,将前向声明头和实际的声明文件合并成一个。为了提供一些上下文,我对转发声明遵循的每日策略如下:

  • 每个头文件都有其“_fwd.hpp”补码,其中包含该头文件中所有可向前声明实体的向前声明
  • 我包括转发声明头,其中转发声明实际内容就足够了
  • 我主要将常规声明头包含在.cpp文件中,并且仅当需要实际的实现信息时(需要实现大小、继承等)
但是,为每个集管配备单独的_fwd.hpp集管会污染项目,并且难以维护。因此,我提出了以下想法:将前向声明和实际声明合并到单个文件中,然后根据包含计数启用它们。我提出了双重包含标题的最初想法

福岛水电站

#if !defined(FOO_FWD_H)
#define FOO_FWD_H
    // Forward declarations goes here
    struct foo;
#else // has forward_declaration, include actual if not included yet

#if !defined(FOO_H)
    #define FOO_H
    struct foo{
       foo(){/*....*/}
    };
    // Normal declarations goes here
#endif // FOO_H

#endif // FOO_FWD_H
如果我包含“foo.hpp”一次,我会得到foo的前向声明,但是如果我在翻译单元中包含第二次,我会得到foo的前向和实际声明,这对我来说是完全正确的。(反正我也在做同样的事情,在页眉中包括fwdecl,在cpp中包括actual)

所以,在上面描述的用例中,它是这样的

bar.hpp

#pragma once

#include "foo.hpp" // forward declaration

struct bar{
    bar(const foo& f);
};
#include "bar.hpp" // bar + 1st inclusion of foo.hpp
#include "foo.hpp" // included 2nd time, actual implementation enabled

bar::bar(const foo& f){
    f.rab(); // requires actual implementation
}
#if !defined(FOO_FWD_HPP)
#define FOO_FWD_HPP

// forward declarations go here

struct foo;

#endif // FOO_FWD_HPP

#if !defined(FOO_FWD_ONLY)
// includer wants the full monty
#if !defined(FOO_HPP)
#define FOO_HPP

// normal declarations go here

struct foo{
   foo(){/*....*/}
};

#endif // FOO_HPP
#endif // FOO_FWD_ONLY

#undef FOO_FWD_ONLY
#pragma once

// only need forward declarations from foo.hpp
#define FOO_FWD_ONLY
#include "foo.hpp"

struct bar {
    bar(const foo& f);
};
#include "bar.hpp"
#include "foo.hpp"

bar::bar(const foo& f){
    f.rab(); // requires actual implementation
}
bar.cpp

#pragma once

#include "foo.hpp" // forward declaration

struct bar{
    bar(const foo& f);
};
#include "bar.hpp" // bar + 1st inclusion of foo.hpp
#include "foo.hpp" // included 2nd time, actual implementation enabled

bar::bar(const foo& f){
    f.rab(); // requires actual implementation
}
#if !defined(FOO_FWD_HPP)
#define FOO_FWD_HPP

// forward declarations go here

struct foo;

#endif // FOO_FWD_HPP

#if !defined(FOO_FWD_ONLY)
// includer wants the full monty
#if !defined(FOO_HPP)
#define FOO_HPP

// normal declarations go here

struct foo{
   foo(){/*....*/}
};

#endif // FOO_HPP
#endif // FOO_FWD_ONLY

#undef FOO_FWD_ONLY
#pragma once

// only need forward declarations from foo.hpp
#define FOO_FWD_ONLY
#include "foo.hpp"

struct bar {
    bar(const foo& f);
};
#include "bar.hpp"
#include "foo.hpp"

bar::bar(const foo& f){
    f.rab(); // requires actual implementation
}
但正如你所能想象的,这种方法存在问题。最大的问题是,如果另一个标题tar.hpp包含foo.hpp,而tar.hpp包含在bar.hpp中,则会导致实际实现暴露在bar.hpp中,从而无法实现此目的。此外,当bar.hpp中需要实际实现foo.hpp时,它必须包含两次,这看起来很奇怪(linter和像iwyu这样的工具可能会有问题)

所以问题归根结底是这样的,我们真的能以这样一种方式使它工作吗

  • 包含使用此习惯用法的标头不会干扰其他标头的包含状态
  • 在需要实际实施时消除双重包含的需要
提前谢谢

更新:(格林威治时间19月30日10:57下午+2)

基于@IanAbbott的答案的成语改进版本:

现场试用:

foo.hpp(我们单一的fwdecl和decl习惯用法实现标题)

/(mgilor):我们有很多样板代码,
//也许x-macro的概念可以帮助我们摆脱样板文件,转而使用
//单独的文件?
#如果已定义(仅限FOO_FWD_)
#undef FOO_FWD_HPP//防止在其他头上意外包含实现
#恩迪夫
#如果已定义(仅限FOO_FWD_)&&!已定义(FOO_FWD_水电站)
#定义FOO_FWD_水电站
//转发声明到这里
结构foo;
#艾利夫!已定义(仅限FOO_FWD_)
//includer想要一个完整的月
#如果!已定义(福乌水电站)
#定义FOO_水电站
//实际声明在这里
结构foo{
foo(){/*....*/}
void do_things(){}
};
#endif//FOO_水电站
#endif//FOO_FWD_水电站
//取消定义宏,使未来包含不会受到影响
#仅适用于未定义的FOO_FWD_
焦油hpp(仅限fwdecl食品消费者)

#pragma一次
#仅定义FOO_FWD_
#包括“foo.hpp”//此标题需要转发声明
#ifdef FOO_FWD_水电站
#pragma消息(_文件_“具有foo的前向声明”)
#恩迪夫
#ifdef FOO_水电站
#pragma消息(_文件_“具有完整的foo声明”)
#恩迪夫
结构焦油{
焦油(foo&f){}
};
bar.hpp(fwdecl仅为foo的消费者,也消耗tar.hpp)

#pragma一次
#仅包括“焦油量hpp”//foo fwdecl消耗的焦油量
#仅定义FOO_FWD_
#仅包括“foo.hpp”//bar需要fwdecl
#ifdef FOO_FWD_水电站
#pragma消息(_文件_“具有foo的前向声明”)
#恩迪夫
#ifdef FOO_水电站
#pragma消息(_文件_“具有完整的foo声明”)
#恩迪夫
结构条{
酒吧(富富);;
};
酒吧cpp(酒吧和美食的12月份消费者)

#包括“bar.hpp”
#包含“foo.hpp”//second包含,应启用完整定义
#ifdef FOO_FWD_水电站
#pragma消息(_文件_“具有foo的前向声明”)
#恩迪夫
#ifdef FOO_水电站
#pragma消息(_文件_“具有完整的foo声明”)
#恩迪夫
酒吧:酒吧(foo&ref){
参考:做事;
}
baz.hpp(无相关性)

#pragma一次
结构baz{
void do_baz();
};
baz.cpp(foo&baz的12月份消费者)

#包括“baz.hpp”
#包括“foo.hpp”//foo之前不包括,但因为没有定义foo_FWD_ONLY
//baz.cpp将获得完整声明。
#ifdef FOO_FWD_水电站
#pragma消息(_文件_“具有foo的前向声明”)
#恩迪夫
#ifdef FOO_水电站
#pragma消息(_文件_“具有完整的foo声明”)
#恩迪夫
void baz::do_baz(){
福福;
f、 做事();//完全好。
}
main.cpp(消费应用程序)

//消费应用程序
#包括“tar.hpp”
#包括“bar.hpp”
#include“foo.hpp”//已经有以前的foo-fwdecl,所以第二次包含将启用完整声明。
//(此外,FOO_FWD_ONLY未定义,因此首次包含也将启用它)
#包括“baz.hpp”
内部主(空){
福福;
焦油t(f);
b栏(f);
baz-bz;
}
编译时的输出:

    tar.hpp:7:13: warning: tar.hpp has forward declaration of foo 
    bar.hpp:8:13: warning: bar.hpp has forward declaration of foo 
    bar.cpp:6:13: warning: bar.cpp has forward declaration of foo 
    bar.cpp:9:13: warning: bar.cpp has full declaration of foo 
    baz.cpp:9:13: warning: baz.cpp has full declaration of foo 
    tar.hpp:7:13: warning: tar.hpp has forward declaration of foo 
    bar.hpp:8:13: warning: bar.hpp has forward declaration of foo 
这是一个