c ++:如何为每个特征制作特定的二进制文件(可执行文件)?

时间:2017-08-01 21:01:57

标签: c++ templates metaprogramming

我正在开发一个有很多特质类型的项目。如果我在相同的代码库中编译每个特征,那么发布的二进制文件就会非常大。

我正在考虑使用宏为每个特定的特征构建一个二进制文件 - 从业务逻辑的角度来看,这是完全合理的。

然而,我意识到,如果我想减少代码库,我需要在每个模板cpp文件的末尾都有这个long if / elif堆。这听起来像是一件非常乏味的事情。

我想知道你以前是否遇到过这种问题,这里最简洁的解决方案是什么?

#include "MyTraits.hpp"
#include "Runner.hpp"
int main(){
    #if defined USE_TRAIT_1
    Runner<Trait1> a;
    #elif defined USE_TRAIT_2
    Runner<Trait2> a;
    #elif defined USE_TRAIT_3
    Runner<Trait3> a;
    #endif
    return 0;
}

2 个答案:

答案 0 :(得分:0)

我不完全确定我的答案会解决问题的根本原因。但建议的解决方案至少可能看起来更“整洁”。

@JeffCharter http://localhost:4200背后的基本思想是有道理的,但我不喜欢将代码(在本例中为类型名称)嵌入到makefile中的想法。所以我详细阐述了它,并考虑到以下目标:

  • 使main()的内容简短易懂
  • 避免污染makefile
  • 尽可能避免使用宏

我最终得到了以下解决方案,该解决方案需要一个可以在makefile中定义的数字宏。请注意它使用C ++ 17的constexpr if,因此如果您发现它很有用,请确保您的编译器支持它。

constexpr int traitID = TRAIT_ID; // TRAIT_ID is a macro defined somewhere else.

template <typename T>
struct Wrapped // helper struct
{
    using Type = T;
};

auto trait()
{
    // Although it may look not that different from macros, the main difference
    // is that here all the code below gets compiled.
    if constexpr (traitID == 1)
        return Wrapped<Trait1>{};
    else if constexpr (traitID == 2)
        return Wrapped<Trait2>{};
    else if constexpr (traitID == 3)
        return Wrapped<Trait3>{};
    // add more cases if necessary
}

int main() // the contents of 'main' seems to have become more readable
{
    using Trait = decltype(trait())::Type;
    Runner<Trait> a;
    return 0;
}

此外,这里是proposal

答案 1 :(得分:0)

如果您想要在特定编译单元中明确指定模板,则应使用extern template关键字。

// Runner.hpp
//define your template class
template <class runner_trait>
class Runner {
...
};

//This tells the compiler to not instanciate the template,
// if it is encounterd, but link to it from a compilation unit.
// If it is not found, you will get a linker errer.
extern template Runner<Trait1>;
extern template Runner<Trait2>;
extern template Runner<Trait3>;
Runner_trait1.cpp

// the template class keyword tell the compiler to instanciate the template in this compilation unit.
template class Runner<Trait1>;

// The files for Runner_trait2.cpp and  Runner_trait3.cpp look identical,
// except for the trait after Runner