我想知道是否有一种优雅的方法来解决这个问题。假设有一个共同的标题,例如
// common.h
#ifndef COMMON_H
#define COMMON_H
#define ENABLE_SOMETHING
//#define ENABLE_SOMETHING_ELSE
#define ENABLE_WHATEVER
// many others
#endif
现在包含此文件,让我们说100个其他头文件,各种#define
用于启用或禁用仅限于1-2个文件的代码部分。
每次更改一个#define
时,整个项目似乎都在重建(我正在使用Xcode 5.1),这很有意义,因为必须在代码周围完全替换,编译器可以&# 39;不知道它在哪里被使用过。
我试图找到一种更好的方法来管理它,以避免长时间的编译,因为这些定义确实已经多次改变。将每个定义拆分到相应的文件/文件中可能是一种解决方案,但我喜欢将所有内容打包在一起的实用方法。
所以我想知道是否有一种通常用来解决这个问题的模式,我在想
// common.h
class Enables
{
static const bool feature;
};
// common..cpp
bool Enables::feature = false;
在编译优化二进制文件时,这在语义上是否等效? (例如,false enable中的代码将完全消失)。
答案 0 :(得分:2)
这里有两个不同的问题:
将相应文件/文件中的每个定义拆分可能是一个解决方案,但我希望将所有内容打包在一起的实用方法。
这是你的第一个问题。如果我没有正确理解,如果你有多个功能区域,你不必为每个功能区域包含一个标题(但是所有内容都有一个标题)。
应用以下步骤:
按按功能划分代码到不同的标头中;每个标题应包含(最多)单个#define FEATURESET
启用的内容(并且与FEATURESET宏的存在完全无关)。
确保每个标头只编译一次(在每个功能标题文件的开头添加#pragma once
)
根据您定义的功能添加一个执行#if
或#ifdef
的便捷标题文件,并根据需要包含功能文件:
// parsers.h
// this shouldn't be here: #pragma once
#ifdef PARSEQUUX_SAFE
#include <QuuxSafe.h>
#elif defined PARSEQUUX_FAST
#include <QuuxFast.h>
#else
#include <QuuxSafe.h>
#endif
// eventually configure static/global class factory here
// see explanation below for mentions of class factory
客户代码:
#include <parsers.h> // use default Quux parser
#define PARSEQUUX_SAFE
#include <parsers.h> // use safe (but slower) Quux parser
所以我想知道是否存在通常用于解决此问题的模式
这是你的第二个问题。
通过C ++中的功能启用功能的规范方法是根据基类,类工厂和通用接口编程来定义功能API。
// common.h
#pragma once
#include <Quux.h> // base Quux class
struct QuuxFactory
{
enum QuuxType { Simple, Feathered };
static std::unique_ptr<Quux> CreateQuux(int arg);
static QuuxType type;
};
// common.cpp:
#include <common.h>
#include <SimpleQuux.h> // SimpleQuux: public Quux
#include <FeatheredQuux.h> // FeatheredQuux: public Quux
std::unique_ptr<Quux> QuuxFactory::CreateQuux(int arg)
{
switch(type) {
case Simple:
return std::unique_ptr<Quux>{new SimpleQuux{arg}};
case Feathered:
return std::unique_ptr<Quux>{new FeatheredQuux{arg}};
};
// TODO: handle errors
}
客户代码:
// configure behavior:
QuuxFactory::type = QuuxFactory::FeatheredQuux;
// ...
auto quux = QuuxFactory::CreateQuux(10); // creates a FeatheredQuux in this case
这具有以下优点:
它很简单,不使用宏
可以重复使用
它提供了足够的抽象级别
它不使用任何宏(如“在所有”中一样)
假设Quux
功能的实际实现仅包含在一个文件中(作为实现细节,仅编译一次)。你可以在任何你想要的地方包含common.h,它根本不包括SimpleQuux.h和FeatheredQuux.h。
作为通用指南,您应该编写代码,这样它就不需要运行宏。如果这样做,您会发现要添加的任何宏都很容易添加。相反,如果您从一开始就依赖宏来定义您的API,那么代码将无法使用(或接近无法使用)。
答案 1 :(得分:0)
有一种方法可以拆分定义,但仍然使用一个中央配置标题。
main_config.h
(它必须没有包含警戒或#pragma once
,因为如果在一次编译中多次包含main_config.h
,则会导致奇怪的结果单元):
#ifdef USES_SOMETHING
#include "something_config.h"
#endif
#ifdef USES_WHATEVER
#include "whatever_config.h"
#endif
something_config.h
(由于与main_config.h
相同的原因,不得包含警戒):
#define ENABLE_SOMETHING
所有源文件和文件头文件#include
仅main_config.h
,但在包含之前,他们必须声明它们所引用的部分:
<强> some_source.cpp
强>:
#define USES_SOMETHING
#include "main_config.h"
<强> some_other_file.h
强>:
#define USES_WHATEVER
#include "main_config.h"