【问题标题】:Is there a way to detect portably that a standard header is included using macros?有没有办法使用宏来检测是否包含标准头文件?
【发布时间】:2015-03-04 02:24:30
【问题描述】:

我想与boost::swap 等效,并且在我的环境中,可以包含或不包含标准标头。取决于项目许可和其他内容。
我想让部分代码受到保护检测器的保护:

让我们考虑一个编译单元。
项目特定的,预先写好的潜力包括:

#include <algorithm> // (or <utility> for C++11 projects)

稍后在我的交换实用程序标头中包含的项目代码中:

namespace MyCompany
{
  template<class T1, class T2>
  void swap(T1& left, T2& right)
  {
     #ifdef _ALGORITHM_   // you get the idea.
       std::swap(left, right);
     #else
       // fallback impl
     #endif
  }
}

我简化了,因为我们不是在这里讨论 ADL 技巧的细节,但它会被包括在内。
这里是我在说什么的参考,但这与这个问题无关:
http://www.boost.org/doc/libs/1_57_0/boost/core/swap.hpp

所以这个问题是关于如何检测标准标题包含_ALGORITHM_ 守卫出现在 Visual Studio 提供的标题中,但我在 http://www.cplusplus.com/reference/algorithm/ 上没有看到它应该有任何我可以检查的宏。

最后一点:这个问题有点偏向XY。我真正想要的是检测std::swap函数的存在,而不是标题。)

【问题讨论】:

  • 所以你想要反过来?使用专门的交换作为后备?
  • 假设,作为惯例,我们代码库的客户端将使用 MyCompany::swap 作为默认交换函数,就像 boost 用户广泛采用 boost::swap 一样。然而,该特殊交换的实现可以在内部使用 std::swap,以防被交换的 T1 和 T2 类型具有 std::swap 的特化。但是,如果此时不包含标准标头(因为我的实用程序不会包含它们,因为尊重更严格的许可规则),我想检测到这一点并且永远不要调用 std::swap。
  • 我尊重您的意图,但从长远来看,这会导致难以追踪的错误;客户端的代码可能会根据它们是否 #include &lt;algorithm&gt; 默默地改变行为,您将不得不处理客户端支持请求
  • how to implement is_swappable...的可能重复项...?
  • 我没有得到“许可规则”位。 std::swap 的许可证与 operator+(int,int) 的许可证相同。当然你不想暗示后者也可以由用户提供?!

标签: c++ utility


【解决方案1】:

您有一个选项可以使您的重载成为比替代方案“更糟糕的匹配”。然后,只有当它们不存在时才会选择您的版本:

#if 0
#include <algorithm>
using std::swap;
#endif

template <typename T>
struct ForceLessSpecialized {
  typedef T TYPE;
};

template <typename T>
void swap (T &, typename ForceLessSpecialized<T>::TYPE &) {
}

void bar () {
  int i;
  swap (i, i);
}  

发生了什么:

当有两个候选函数模板特化时,编译器会执行“函数模板的部分排序”('03 14.5.5.2)。这将检查一个模板的函数模板参数是否可用于专门化另一个模板。

对于每个模板,我们将使用虚拟参数 T1T2,并使用这些类型创建虚拟参数列表:

// std::swap argument list
( T1 &  , T1 & )

// our swap argument list
( T2 &, typename ForceLessSpecialized<T2>::TYPE & )

使用来自std::swap 的虚拟参数专门化我们的交换会得到:

Deduction from First parameter:  T == T1
Deduction from Second parameter:  Non Deduced Context

推导出TT1,推演成功。

使用我们的交换的虚拟参数专门化 std::swap 给出:

Deduction from First parameter:  T == T2
Deduction from Second parameter:  T == ForceLessSpecialized<T2>::TYPE

T的推导类型不一样,属于推导失败。

因此,std::swap 的综合参数可用于特化我们的模板,但我们模板的综合参数不能用于特化 std::swapstd::swap 被视为更专业,因此赢得了部分订单。

【讨论】:

  • 该死的,这是伟大的工作。绝对是一个很好的阅读标准。 14.5.5.2 指的是类,实际的段落是 14.5.6.2,但是有一个链接。谢谢 :) 这很有趣,因为昨天我读了 Herb Sutter 关于“为什么不专门化函数模板”的观点。 gotw.ca/publications/mill17.htm 也很好读
  • @v.oddou:正如你所指出的,最新标准中的段落是 14.5.6.2,我使用的是 '03 标准,它是 14.5.5.2。
【解决方案2】:

C++17 带来了一个新的特性,现在让这成为可能是相关的。
https://en.cppreference.com/w/cpp/preprocessor/include

它叫__has_include
此处示例:#if __has_include(&lt;algorithm&gt;)

编辑:它与问题的要求不同,它只是说明可达性。

【讨论】:

  • 但这会返回一个标头是否存在,而不是它是否已经被包含。
  • 该死的,真的吗?那我还没有深入阅读......(阅读后回来)天哪,你是对的。这不是我想要的问题。这是一个完全不同的功能
猜你喜欢
  • 2018-05-19
  • 1970-01-01
  • 2018-06-23
  • 2021-08-10
  • 2010-10-26
  • 2020-12-22
  • 2017-02-21
相关资源
最近更新 更多