在c++中,如何用回退包装默认标头
In c++, how to wrap default headers with fallback
假设我的代码使用std::array,我想做:
文件:阵列
#pragma once
#ifdef MY_TOOLSET_HAS_STD_ARRAY
#include <array> //recursive include here?
#else
#include <boost/array.hpp>
namespace std
{
using boost::array;
}
#endif
这样我的项目就可以使用std::array而不必关心编译器/平台。一个问题(至少)是,当std::array可用时,include将是递归的,而我真正想要的是(从语义上)"包含如果这个include不存在就会包含的头"。
有什么想法吗?我知道将boost::array拉入std可能也被认为是不好的做法,所以我也对这方面的想法感兴趣。
解决这个"问题"的正确方法是首先不要引入它。
如果您的一些构建环境支持C++11,但其他构建环境不支持,那么请找到一个在所有构建环境下都支持的公共子集并使用它。在这种情况下,该公共子集似乎是Boost。所以你应该使用boost::array
。
还要考虑,如果你发展&使用std::array
进行测试,那么整个代码分支都没有经过测试——使用boost::array
的分支。
我完全支持懒惰编程——但聪明懒惰编程。懒惰编程并不意味着笨拙或笨拙的编程,聪明的懒惰编程也不会像将boost::array
添加到std
命名空间那样调用Undefined Behavior。说"我不想浏览我所有的代码并将std::array
更改为boost::array
"并不是引入黑客和未定义行为的好理由。它可以像调用sed
来进行所有这些更改一样简单,而且可能只需要5分钟。
您可以使用C++11之前的"template-typedef变通方法",它不涉及#定义类型名称,但会使使用类型的语法变得更丑陋:
#ifdef MY_TOOLSET_HAS_STD_ARRAY
#include <array>
#else
#include <boost/array.hpp>
#endif
template <typename T, size_t N>
struct fixed_array
{
#ifdef MY_TOOLSET_HAS_STD_ARRAY
typedef std::array<T, N> type;
#else
typedef boost::array<T, N> type;
#endif
};
然后您对该类型的使用变为:
typename fixed_array<char, 4>::type some_chars;
然而,仅仅使用boost::array
会简单得多。这意味着需要测试的排列更少,从而降低了代码库的维护成本。
这绝对是宏的用例之一:
// in "my_fixed_array.h"
#ifdef MY_TOOLEST_HAS_STD_ARRAY
#include <array>
#define FIX_ARRAY std::array
#else
#include <boost/array.hpp>
#define FIX_ARRAY boost::array
#fi
// anywhere else
#include "my_fixed_array.h"
FIX_ARRAY<char, 4> some_chars;
这样你就不必到处做一些顽皮的事情,比如把东西放进namespace std
。
根据编译器实现的健全程度(在这方面大多数都很好),您可以简单地依赖include路径搜索顺序。默认系统包含路径通常在用户指定的"附加"包含路径之前进行搜索。
因此,如果您有一个名为array
的标头位于非标准包含路径中,则可以假设如果标准<array>
标头不存在,则它将仅包含,因为否则将首先找到系统标头。请注意,您甚至不需要使用此技术的特征检测goop。
(我没有说它很漂亮——这有点滥用构建环境,尽管它相当安全。)
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 如何使用默认参数等选择模板专业化
- 具有默认模板参数的多态类的模板推导失败
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 如何在c++17中制作一个模板包装器/装饰器
- std::vector的包装器,使数组的结构看起来像结构的数组
- 当函数模板参数是具有默认参数的类模板时,函数模板参数的推导如何执行
- 初始化具有非默认构造函数的std::数组项的更好方法
- 何时提供默认参数作为模板参数
- 如何在c++迭代器类型中包装std::chrono
- 是默认情况下分配给char数组常量的值
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话
- 是否有 C++20 浮点数的包装器,使我能够默认宇宙飞船操作员?
- 非默认可构造和 std::引用包装器替代项的序列化
- 带有默认参数的宏包装函数调用
- swig-包装到c#时,没有默认的std ::列表,我该怎么做
- 如何配置要使用默认的HTML包装器构建的Emscripten目标
- 将包装器与函数指针一起使用来处理参数的默认值
- 对包装类中的参数使用默认值
- 在c++中,如何用回退包装默认标头