【问题标题】:Why does std::is_array return false for std::array?为什么 std::is_array 为 std::array 返回 false?
【发布时间】:2016-12-02 03:25:08
【问题描述】:

由于std::array<>std::is_array<>都是在C++11中引入的,所以编译失败似乎很奇怪:

#include <array>
#include <type_traits>

static_assert(std::is_array<std::array<int,2>>::value);

有没有一种简单的方法来检查某个东西是否是一个数组,包括T[N]std::array&lt;T,N&gt; 的可能性?

【问题讨论】:

  • std::array 根本不是一个数组。他们只是这么称呼它,因为它比std::array_wrapperstd::better_array 更方便。
  • @user2357112:由于is_array&lt;&gt; 的含义是由定义array&lt;&gt; 的同一语言的完全相同版本决定的,因此“数组不是数组”的概念似乎很荒谬,不是吗?
  • 智能指针也不通过is_pointer。如果std::is_array 是特殊情况下的std::array,那么std::is_array 的用处就会降低,而使std::array 成为一个实际的数组将首先破坏std::array 的全部意义。只是不要让这些名称让您感到困惑。
  • 鉴于引入了std::array,一个更好的名称应该是std::is_carray。但是特质确实很混乱,并且按照自己的规则和古怪的名字发挥作用。比如根据stdstd::complex&lt;double&gt;就不是arithmetic。 (std::is_arithmetic&lt;std::complex&lt;double&gt;&gt; 是假的)。我认为这是因为获得正确的“概念”是困难的,即使是简单的。我预计在概念语言中会出现更多这样的问题,在这种语言中,事物的含义并不总是它们看起来的样子。

标签: c++ arrays c++11 typetraits


【解决方案1】:

std::is_array 被定义为仅适用于看起来像 T[]T[N] 的类型。 std::array 不包括在内。

您不能在标准下将std::is_array 修改或特化为true_typestd::array;这将使您的程序格式错误,无需诊断。特化std内的类型时,结果必须与标准一致,此处特指标准。 (此外,对std 中的其他模板这样做是非常可疑的非法行为)。

你可以创建自己的is_array trait:

namespace notstd {
  template<class T>
  struct is_array:std::is_array<T>{};
  template<class T, std::size_t N>
  struct is_array<std::array<T,N>>:std::true_type{};
  // optional:
  template<class T>
  struct is_array<T const>:is_array<T>{};
  template<class T>
  struct is_array<T volatile>:is_array<T>{};
  template<class T>
  struct is_array<T volatile const>:is_array<T>{};
}

然后在别处使用 notstd::is_array&lt;T&gt; 来检测 C 样式数组或 C++ std::array

【讨论】:

    【解决方案2】:

    ISO/IEC 14882:2011,§ 20.9.4.1,表 47 说明:

    • 模板:模板结构is_array;

    • 条件:T是已知或未知范围的数组类型(3.9.2)

    • 注释:类模板数组(23.3.2)不是数组类型。

    所以,断言应该失败。

    虽然您可以按照@0x499602D2 的建议对is_array 进行专门化,但如果您这样做了,您应该在另一个命名空间中这样做,因为您不应该尝试更改标准化函数的含义。

    【讨论】:

    • 感谢您的参考。想要区分 C++ 数组和 C 数组的代码不能使用std::is_class&lt;&gt;吗?
    • @JohnZwinck 是的,它可以。我想标准作者认为这样会更有用
    • @harmic 您的最后一段导致程序格式错误,不需要诊断; std 命名空间内的特征类的特化不得违反标准中记录的特征类公理。
    • @Yakk,我不确定你的意思,因为我的最后一段建议你不应该尝试这样做。无论如何,我已经把措辞收紧了一点。
    • 这应该被称为std::is_c_array,与c_str() 不同。现在,对于新手来说,这是一个令人尴尬和无法解释的边界,为什么明确称为“数组”的构造不是数组。
    【解决方案3】:

    Cppreference 提供了这种可能的实现方式:

    template<class T>
    struct is_array : std::false_type {};
    
    template<class T>
    struct is_array<T[]> : std::true_type {};
    
    template<class T, std::size_t N>
    struct is_array<T[N]> : std::true_type {};
    

    不幸的是,它没有为std::array 提供专业化。你可以这样做:

    template<class T>
    struct is_array : std::is_array<T> {};
    template<class T, std::size_t N>
    struct is_array<std::array<T, N>> : std::true_type {};
    

    【讨论】:

    • 这个解决方法感觉有点冒险......可能会破坏第三方库头代码,具体取决于包含顺序
    • @M.M 那你有什么建议?直接在std内部进行专业化?
    • 我建议理解 std::is_array 仅指 C 风格的数组,而不是 std::array ,如果你想要一个匹配这两个东西的特征,那么就创建你自己的特征
    • @MM 太好了。那你应该回答一下。
    • @0x499602D2 将您的is_array 放入namespace notstd 或其他东西;并明确表示它不会进入std。如所写,目前尚不清楚您是建议某人将其放入根命名空间、他们自己的命名空间,还是将其注入std 或同样可怕的东西。
    猜你喜欢
    • 1970-01-01
    • 2020-09-13
    • 2015-12-14
    • 2023-03-14
    • 2018-02-23
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多