【问题标题】:Compile-time check that all array values are filled编译时检查是否填充了所有数组值
【发布时间】:2016-10-06 08:39:47
【问题描述】:

这个:

constexpr const std::array<int, 3> {{
  0,
  1
}};

编译正常。

但是如何(在编译时)检查整个数组是否已填充?可能是一些static_assert

【问题讨论】:

  • “填充”是什么意思?你的意思是初始化?
  • @TartanLlama 是的,已初始化。检查程序员在改变大小后没有忘记添加一个值。
  • 没有办法测试一个对象是否已经初始化,但我认为剩余的元素是值初始化的(即在你的情况下为零)。 (换句话说,它就像一个普通数组。)
  • 是的,除非您需要编写一个包装函数来为您创建数组;事后你无法判断。

标签: c++ compile-time static-assert


【解决方案1】:

您可以编写一个包装器来为您生成数组并进行检查:

template <typename T, std::size_t N, typename... Ts>
std::array<T, N> make_array (Ts&&... ts) {
    static_assert(N == sizeof...(Ts), "Must supply N arguments");
    return {{ std::forward<Ts>(ts)... }};   
}

但是使用该函数,您也可以从参数中推断出数组的大小:

template <typename T, typename... Ts>
std::array<T, sizeof...(Ts)> make_array (Ts&&... ts) {
    return {{ std::forward<Ts>(ts)... }};   
}

【讨论】:

  • TartanLlama,为什么我不能使它成为 constexpr? Clang 3.8.1 说 non-constexpr function 'forward&lt;int&gt;' cannot be used in a constant expression return {{ std::forward&lt;Ts&gt;(ts)... }}; ?
  • @vladon std::forward 在 c++11 中不是 constexpr(参见 here)。如果您只是要使用内置类型或小型类型,则可以只通过值传递,或者通过 const ref 传递。或者,您可以编写一个 constexpr 转发函数。
  • @vladon 嗯,你能发布一个例子吗? This 似乎工作正常。
  • 抱歉,这是我的错,不知怎的,我使用带有 clang 的旧 libcxx,其中 std::forward 不是 constexpr :(
【解决方案2】:

作为对 TartanLlama 答案的增强,我会将初始化例程包装到另一个宏中,以提供创建正确文档和更好可读性的可能性(因为操作提到这是对其他程序员的安全检查)。

template <typename T, T ...ts>
struct ArrayInitializer { 
    const std::array<T, sizeof...(ts)> ARRAY = {{ ts... }}; 
};

/*
 * @document me
 */
#define MAKE_ARRAY(name, ...) \
    constexpr const auto name = ArrayInitializer<int,  ##__VA_ARGS__ >().ARRAY;

// Create array with x elements    
MAKE_ARRAY(arrayName, 1, 2, 3, 4);

【讨论】:

  • 这比auto arrayName = make_array(1,2,3,4); 好多少? (特别是 ##__VA_ARGS__ 没有受到标准的祝福。)
  • 初始化完成的方式是没有问题的,因为这两种方法都只在编译时使用并且服务于相同的目的,我的意思是为使用的其他程序员提供一个可读的接口数组,尤其是在使用 doxygen 等解析源时...
  • 事实上 VA_ARGS 是标准的一部分。引用 Wikipedia (en.wikipedia.org/wiki/Variadic_macro):“变量参数宏于 1999 年在 C 语言标准的 ISO/IEC 9899:1999 (C99) 修订版中引入,并于 2011 年在 ISO/IEC 14882:2011 (C++11) 中引入) C++ 语言标准的修订版。”
  • 是的,我知道__VA_ARGS__ 是标准的一部分——它前面是非标准的##(预处理器标记粘贴运算符)(尽管是一个常见的扩展)。跨度>
  • 为此使用宏似乎非常丑陋且没有必要。其中哪一部分比我的答案更具可读性和可记录性?即使您一生中从未编写过模板,auto arr = make_array&lt;int&gt;(1,2,3); 对我来说似乎也是一种自我记录。
猜你喜欢
  • 2017-03-28
  • 2021-04-14
  • 2019-12-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2017-03-17
  • 2020-07-11
  • 2011-05-19
相关资源
最近更新 更多