C++ 在c++;,如何使用回退包装默认标题

C++ 在c++;,如何使用回退包装默认标题,c++,c++11,boost,C++,C++11,Boost,假设我的代码使用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 #pragma一次 #如果定义我的工具集有标准数组 #包含//递归包含在这

假设我的代码使用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
#pragma一次
#如果定义我的工具集有标准数组
#包含//递归包含在这里?
#否则
#包括
名称空间标准
{
使用boost::数组;
}
#恩迪夫
这样我的项目就可以使用std::array,而不必关心编译器/平台。一个问题(至少)是,当std::array可用时,include将是递归的,而我真正想要的是(语义上)“包含如果这个include不存在本应包含的头”


有什么办法吗?我知道将boost::array拉入std也可能被认为是不好的做法,所以我对这方面的想法也很感兴趣。

这绝对是宏的使用案例之一:

// 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;
//在“my\u fixed\u array.h”中
#如果定义MY_TOOLEST_有STD_数组
#包括
#定义固定数组std::ARRAY
#否则
#包括
#定义修复数组boost::ARRAY
#fi
//其他地方
#包括“my_fixed_array.h”
修复数组中的一些字符;

这样,你就不必到处做一些淘气的事情,比如把东西放进
命名空间std

根据编译器实现的健全程度(大多数在这方面都很好),您可以简单地依赖include路径搜索顺序。默认系统包含路径通常在用户指定的“附加”包含路径之前搜索

因此,如果在非标准包含路径中有一个名为
array
的标头,则可以假定只有在标准
标头不存在时才会包含该标头,否则会首先找到系统标头。请注意,您甚至不需要使用这种技术的特性检测工具

(我没有说它很漂亮——这有点滥用构建环境,尽管这是一个相当安全的环境。)

您可以使用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
};
#如果定义我的工具集有标准数组
#包括
#否则
#包括
#恩迪夫
模板
结构固定数组
{
#如果定义我的工具集有标准数组
typedef std::数组类型;
#否则
typedef boost::数组类型;
#恩迪夫
};
然后,您对该类型的使用变为:

typename fixed_array<char, 4>::type some_chars;
typename固定数组::键入一些字符;

然而,仅仅使用
boost::array
就相当简单了。这意味着您需要测试的排列更少,因此降低了代码库的维护成本。

解决这个“问题”的正确方法是一开始就不引入它

如果您的某些构建环境支持C++11,但其他构建环境不支持,那么请查找所有构建环境下支持的公共子集并使用它。在这种情况下,公共子集似乎是Boost。因此,您应该使用
boost::array

还需要考虑的是,如果您使用
std::array
开发和测试,那么您就没有测试整个代码分支——使用
boost::array
的分支


我完全支持懒惰编程——但是聪明的懒惰编程。懒惰编程并不意味着黑客或笨拙的编程,聪明的懒惰编程也不会调用未定义的行为,就像将
boost::array
添加到
std
命名空间那样。说“我不想检查所有代码并将
std::array
更改为
boost::array
”并不是引入黑客和未定义行为的好理由。它可以像调用
sed
来进行所有这些更改一样简单,而且可能只需要5分钟。

这是未定义的行为。使用另一种方法。对于
array
Boost.TR1的情况,应该做正确的事情。实际上,在
std
中放入内容在技术上是未定义的行为,这不是一种坏做法(但在调用鼻魔之前,它应该可以正常工作)。我认为你最好把你的头命名为不同的名称(或者像Boost那样把它放在不同的目录中)。如果你需要处理C++11之前的编译器,为什么不直接使用
Boost::array
?即使在这种情况下,您也很可能可以访问
中提供的
std::tr1::array
。我不能代表其他人说话,但就个人而言,我宁愿(非法)扩展
std
,也不愿使用宏作为类型名…@Cameron我宁愿使用宏。至少生成的代码是合法的,因为您不需要宏。使用
namespace my{#ifdef my#u toolsest_拥有使用ARRAY=STD::ARRAY的STD#u数组;#else使用ARRAY=boost::ARRAY;#endif}
@Praetorian我假设练习的重点是C++11不可用。@NeilKirk是的,很公平。如果您还需要支持较旧的编译器,我个人会坚持在任何地方使用
boost::array
。所以我并不反对……这是一种选择。但这是一个有很多人参与的项目,如果能处理每个人都不知道“哦,我必须使用boost::array”的情况,那就太好了…因为它是在开发平台上工作的。@user109078不幸的是,这是您的经理需要解决的问题。开发人员不应该使用Prod中未使用的编译器进行开发。它们是,但我们为windows和linux发布了版本…并且他们在windows上使用Visual Studio。