2016-10-30 50 views
-1

我正在实现一个库,并且使用了具有一些不同实现的抽象类/接口。我想允许用户使用配置文件来选择特定的实现,例如config.h。我有两个问题:C++无宏配置方法

  • 如何实现这个没有宏?
  • 我使用继承来实现子类,但我不想在运行时动态选择类,我们仍然可以实现这个吗?

我在寻找C++ 11解决方案,但也欢迎C++ 14和C++ 17。

举个例子:

#include "config.h" 

class library1_base { 
    virtual void blah() = 0; 
    virtual void bleh() = 0; 
} 

#ifdef LIB1_USE_IMPL1 
class impl1_lib1 : library1_base { ... }; 
using library1 = impl1_lib; 
#else 
class impl2_lib1 : library1_base { ... }; 
using library1 = impl2_lib; 
#endif 

class library2_base { 
    virtual void ah() = 0; 
    virtual void oh() = 0; 
} 

#ifdef LIB2_USE_IMPL1 
class impl1_lib2 : library2_base { ... }; 
using library2 = impl1_lib2; 
#else 
class impl2_lib2 : library2_base { ... }; 
using library2 = impl2_lib2; 
#endif 

config.h如下(使用宏)

#define LIB1_USE_IMPL1 
#define LIB2_USE_IMPL2 

他们如何使用:

library1 x; // now this library1 should be using impl1_lib1 
x.blah(); 
x.bleh(); 
library2 y; // now this library2 should be using impl2_lib2 
y.ah(); 
y.oh(); 
+0

downvoter ..请评论,以便我可以改善我的问题。 – w00d

+0

您必须显示示例代码才能显示您希望的目标。有人会最有可能标记你的帖子。 –

+0

确定@NickPavini增加了一个使用宏来做我想要的例子 – w00d

回答

1

首先,问自己“怎么了我要选择配置,为什么?“ (宏)是无处不在的(你可以将它们定义为编译器标志和代码),但是它们缺少范围限定功能(它们是全局的,不能被定义为名称空间本地),所以它们很容易命名碰撞。

如果是后者你的关心,你可以定义一个特殊的配置类(ES)与类型定义/常量,像这样:

namespace myapp { 
    struct Config { 
     class library : library_base { ... } 
     using other_library = some_other_library; 
     using version_t = int; 
     static const version_t VERSION = 1; 
    } 
} 

但选择所需的配置,你就必须包括一个多个configXXX.h文件或进行配置类模板,并有多个专业化每个配置,就像这样:

enum class ConfigType { 
    JPEG, PNG 
}; 
template <ConfigType type> struct Configs; 
template <> struct Configs<ConfigType::JPEG> { 
    using library = libjpeg; 
}; 
template <> struct Configs<ConfigType::PNG> { 
    using library = libpng; 
}; 
... 
static const ConfigType CONFIG_TYPE = ConfigType::JPEG; 
... 
using Config = Configs<CONFIG_TYPE>; 
using library = Config::library; 

更新#1:在后面的例子中,组成似乎是最好的解决方案(我已经改名的东西,所以他们做出一点更有意义):

// configs.hpp 
enum class AudioType { 
    MP3, OGG 
}; 
template <AudioType type> struct AudioConfigs; 
template <> struct AudioConfigs<AudioType::MP3> { 
    using Library = libmp3; // of course, you can define class in-place instead of typedef 
}; 
template <> struct AudioConfigs<AudioType::OGG> { 
    using Library = libvorbis; 
}; 

enum class ImageType { 
    JPEG, PNG 
}; 
template <ImageType type> struct ImageConfigs; 
template <> struct ImageConfigs<ImageType::JPEG> { 
    using Library = libjpeg; 
}; 
template <> struct ImageConfigs<ImageType::PNG> { 
    using Library = pnglib; 
}; 

template <AudioType audiotype, ImageType imagetype> struct Configs { 
    using AudioLibrary = typename AudioConfigs<audiotype>::Library; 
    using ImageLibrary = typename ImageConfigs<imagetype>::Library; 
}; 

// config_setup.hpp - this one you will edit 
#include "configs.hpp" 
using Config = Configs<AudioType::MP3, ImageType::JPEG>; 

// config.hpp 
#include "config_setup.hpp" 
using AudioLibrary = typename Config::AudioLibrary; 
using ImageLibrary = typename Config::ImageLibrary; 

// real code 
#include "config.hpp" 
AudioLibrary audioLibrary; 
audioLibrary.doStuff(); 

替代结构:

template <AudioType audiotype, ImageType imagetype> struct Configs { 
    using Audio = typename AudioConfigs<audiotype>; 
    using Image = typename ImageConfigs<imagetype>; 
}; 
// Options should be accessed like Config::Audio::Library now 

更新#2:(只是为了说明无限的可能性),还有一些可变参数模板的魔力,可以缩短AudioConfigs/ImageConfigs /等。到:

template <AudioConfig config> struct AudioConfigs : public LibraryConfigs<AudioConfig, config, AudioType::MP3, AudioType::OGG, libmp3, libvorbis> { }; 

...完全避免与多个专业的样板代码。然后,您将失去就地定义类的可能性,这就是您在示例中正在做的事情,因此请交叉处理。

+0

这种方法没有扩展,因为我必须为所有可能的配置指定专门化,例如,如果我有超过1个可配置库,该怎么办? – w00d

+0

事实上,它是您可以想象的最方便/灵活/可扩展的方法,因为您可以拥有多个配置类,那么您可以继承,编写,typedef,将它们中的任何一个专门化以形成任何可想象的配置结构。如果您想要更深入的解释,请提供一些例子,说明如何使用宏来做,以及您愿意克服哪些漏洞。 – Dmitry

+0

感谢您帮助德米特里,我为两个图书馆添加了示例,您是否可以调整您的想法。 – w00d