如何选择基于C ++版本的函数实现

时间:2016-04-13 17:48:07

标签: c++ c++11 stl c++14

我重新定义了某些C ++函数对象(STL函数),为它们提供constexpr operator()。我需要这些函数在编译时进行评估以用于模板元编程。 C ++ 14为STL功能库提供了constexpr等价物。目前我正在使用C ++ 11编译代码,但最终可能会升级到C ++ 14。我如何实现这些,如果我升级到C ++ 14,它将自动从STL中选择函数对象,而不是我的自定义实现。
到目前为止我是这样的:

namespace foo {
 template <class T = void>
 struct less {
   constexpr bool operator()(T const& lhs, T const& rhs) const { 
     return lhs < rhs;
   }
 };
}

编辑:我知道如果我只使用std命名我的命名空间,可能会使用__cplusplus。然而,这将是一个糟糕的解决方案,因为我会污染所有其他实例的命名空间foo。

2 个答案:

答案 0 :(得分:4)

选项,方法可能最少,对代码影响最小,首先:

  • 使用编译器的包含文件路径选择不同版本的标题。

  • 编译器版本嗅探和条件编译(例如#ifdef)。

  • 批发代码编辑,可能是自动化的。

编译器嗅探非常脆弱,但很常见。

仅检查__cplusplus的价值通常是不够的。

使用编译器的include路径,例如,首先定义一个标头<relops.hpp>,它只是根据C ++ 14功能定义或命名所有内容,默认实现,并将它放在常规头中包含目录

通过编译器的include路径(例如g {的CPATH和Visual C ++的INCLUDE),如果需要特定的编译器,你可以指导它首先查找<relops.h>在一些其他目录中,用于特定于系统的标题。

这个<relops.h>会自行定义事物,就像你提出的代码一样。

使用条件编译,您可以根据宏来确定编译器和版本,例如__cplusplus_MSC_VER__GNUC__,Mac的内容,可能更多。您可以定义一些符号,例如IS_CPP14。然后,您使用#if IS_CPP14 ... #else ... #endif

答案 1 :(得分:0)

您可以使用基于__cplusplus预处理器的解决方案,而不会污染foo命名空间,其内容如下:

namespace foo {
#if __cplusplus < 201402L
 template <class T = void>
 struct less {
   constexpr bool operator()(T const& lhs, T const& rhs) const { 
     return lhs < rhs;
   }
 };
#else
  using std::less;
#endif
}

这为早于'14的C ++版本定义了foo::less的自定义版本,并为{C}版本的foo::less创建了一个别名(仍可用作std::less)。

(常量201402L来自标准本身。符合C ++ 14的编译器需要将__cplusplus设置为至少这个值。

上述代码可能导致在编译器仅部分支持C ++ 14的情况下使用less的自定义实现,即使该部分支持包含constexpr - qualified {{ 1}}。显然,最新版本的Visual Studio也是如此。我建议这甚至不值得担心;无论如何都应该内联对函数的调用,并且在使用正确符合C ++ 14编译器编译的那一刻,您将获得所需的精确(编译级)行为。或者,您可以扩展预处理器逻辑(即检查编译器特定的宏)以识别已知足够符合的特定编译器版本。