如何正确地将功能填充到std中
How to correctly shim functionality into std?
我最近从Microsoft编译器切换到GCC。在许多事情中,我注意到std::make_unique
变得不可用。这显然是因为make_unique
不是C++11标准的一部分,而微软只是碰巧将其作为扩展。
我们计划很快转到C++14,但与此同时,我编写了这个"shim"函数,并将其放入std
中。
namespace std
{
template<typename T, typename... TArgs>
unique_ptr<T> make_unique(TArgs&&... args)
{
return std::unique_ptr<T>(new T(std::forward<TArgs>(args)...));
}
}
这解决了gcc上的问题。然而,我想这会给微软带来问题,因为这将是一个重复的定义。
有没有一种方法可以正确地将功能填充到std中,这样就不会在不同的编译器/C++标准上造成麻烦?我环顾四周,什么也没想出来。我想也许是一个类似于include guard的东西,用于特定的标准功能?
#ifndef MAKE_UNIQUE_DEFINED
#define MAKE_UNIQUE_DEFINED
// Define make_unique
#endif
遗憾的是,std
似乎没有为特定功能定义包含防护。我还有什么可以做的吗,让这更正确,编译器/c++标准不可知?
实际上你可以。只需将您在文章中提到的两个条件转换为条件宏定义:
#if defined(_MSC_VER) && __cplusplus == 201103L
# define MAKE_UNIQUE_DEFINED 1
#endif
_MSC_VER
检查TU是否使用MSVC编译。这是他们预定义的宏之一。您可以使用它来进一步细化检查,因为它是MSVC的编码版本号- 201103L是当TU编译为C++11时
__cplusplus
的值(这是跨平台的标准) - 如果
__cplusplus
没有为您正确定义(因为Microsoft),您可以使用_MSVC_LANG
宏来代替它
按照您最初的计划,以上内容可用于包裹您的"垫片"。或者与这些版本相关的任何其他MSVC扩展。
作为一种替代方案,以避免重新打开std
命名空间(a no no)。你可以使用名称空间将定义放在一个安全的地方,并控制你的程序如何解释它:
namespace extended_std {
#ifdef MAKE_UNIQUE_DEFINED
inline namespace
#else
namespace
#endif
shim {
// your definition goes here
}
#ifndef MAKE_UNIQUE_DEFINED
using std::make_unique;
#endif
}
宏只是用来控制extended_std::make_unique
所指的内容。它要么创建名称空间inline
,要么将其内容注入封闭的名称空间。或者为std::make_unique
添加using声明。
简单地说,不要在std
中定义新功能。在其他地方定义函数,并安排根据其他答案有条件地使其可用。通常,对于这样的事情,在所有平台上从自己的命名空间中获取它会更容易,直到所有编译器都赶上为止。您需要有一些机制来管理声明并使用兼容性函数的语句。(另一种传统的方法是使用自动配置之类的东西来探查编译环境和应用程序的自定义构建兼容性标头。这很难看,但如果做得好,会导致高级别的可移植性。)
对于一个旨在在不太先进的编译环境中提供新的C++功能的工业级库,有Abseil:https://github.com/abseil/abseil-cpp。如果你有兴趣为一个重要的项目做一些稳健的事情,那么那里的设计决策是很好的。
有一个预定义的宏用于此目的:__cpp_lib_make_unique
请参阅功能测试宏
以下应该是完全可移植的:
#include <memory>
#include <utility>
#ifdef __cpp_lib_make_unique
namespace lib {
using std::make_unique;
}
#else
namespace lib {
template<typename T, typename... TArgs>
std::unique_ptr<T> make_unique(TArgs&&... args)
{
return std::unique_ptr<T>(new T(std::forward<TArgs>(args)...));
}
}
#endif
您最终在另一个名称空间lib
中拥有make_unique
在本例中,但这对于严格一致性是必要的(见§17.4.3.1)
我说应该,因为不幸的是,MSVC并没有定义宏,所以您必须使用_MSC_VER
来处理特定于MS的事情。
- 确切地说,如何解释 std::getline(stream, string) 函数在C++中填充的字符串
- 如何用文本填充 std::vector<int64_t>
- 将空填充但不以空结尾的固定长度字符数组转换为 std::string 的最佳方法
- 如何在<N>不发生内存泄漏的情况下同时(线程安全)填充 c++11 std::map<std::string,std::bitset*>?
- C++初始化/填充静态成员 std::数组元素到特定值
- 组合 std::vector 默认值和填充构造函数
- 使用 'std::generate' 或 'std::fill' 来填充 'arma::mat'
- 如何有效地用枚举填充 2D std::数组
- std :: string的解密具有额外的填充字节
- 与STD :: BITSET的工会成员的结构填充
- 用原始数据填充 std::vector
- 给定一个填充无符号字符**的 C 函数,如何在没有中间副本的情况下用数据填充 std::vector
- 如何填充项目为 8 个字符的集合?(std::set<char [8]>)
- 在 c++ 中填充和分配 std::string
- C++填充一个std::map创建不必要的对象
- std::vector<class> 在调试时填充,但在发布时不填充
- 如何创建 std::vector of char/std::byte,其中第一个字节对齐到 16 个字节,但没有填充
- 如何正确地将功能填充到std中
- 如何从实双打的std::向量中填充复数双打的std::向量
- 直接从 C API 填充 std::string