【问题标题】:Compile time range check in std::array在 std::array 中编译时间范围检查
【发布时间】:2021-08-03 18:27:02
【问题描述】:

我想在编译时对 std::array 执行范围检查。这是一个例子:

#include <iostream>
#include <array>

void rarelyUsedFunction(const std::array<double, 2>& input)
{
    std::cout << input[5] << std::endl;
}

int main()
{
    std::array<double, 2> testArray;
    rarelyUsedFunction(testArray);
}

如果我使用 g++ 编译它,则不会出现警告或错误,尽管未定义对不在数组中的元素的访问。编译后的程序只是打印一些随机值。

g++ 中是否有一个编译器选项可以在编译时执行合适的范围/边界检查?我知道我可以添加“-D_GLIBCXX_DEBUG”,但这只会在运行时执行检查。如果我有一个不经常调用的函数,则不会触发。

我知道,不能在所有情况下都执行这样的范围检查,但在上述情况下,编译器应该能够发现问题!?

【问题讨论】:

  • 我相信这是std::get被数组重载的目的
  • 原则上编译器可以发现问题,但是考虑到std::array和其他人一样只是一个自定义类型,而你传递的参数一般不是编译时常量
  • 对此的编译器警告我认为只是时间问题。
  • @user4581301 编译器警告在这里可能并不总是足够好,因为它依赖于编译器推断该值在编译时是可确定的。当然对于文字来说这是微不足道的,但情况并非总是如此,并且不会以任何方式指示未标记为 constexpr 的索引。编译时检查可以静默地从程序中删除,因此显式请求编译时边界检查的方法仍然有用。
  • 问题是“这样做值得吗?”迟早有人会写支票,这是不可避免的,因为人们就是“那样”。检查是否进入编译器取决于它对编译器的速度和复杂性的影响。

标签: c++ g++ stdarray


【解决方案1】:

正如 cmets 中所提到的,std::get(std::array) 会很好地为您做到这一点,因为它有义务进行此类边界检查:

I 必须是 [0, N) 范围内的整数值。这是在编译时强制执行的,而不是 at() 或 operator[]。

在您的示例中,它看起来像这样:

void rarelyUsedFunction(const std::array<double, 2>& input)
{
    std::cout << std::get<5>(input) << std::endl; // <---- Compilation error!
}

如果索引不只是文字,你仍然可以使用“复杂”代码计算它,只要你设法将它填充到 constexpr 变量中:

void rarelyUsedFunction(const std::array<double, 2>& input)
{
    constexpr std::size_t index = /* Whatever, as long as it compiles... */;
   
    std::cout << std::get<index>(input) << std::endl;
}

显然,无论哪种情况,这都涉及向编译器提供硬保证,即在编译时索引是已知的。

【讨论】:

  • 我还在学习有关 c++11 的新知识 =)
  • 作为一个关于在编译时必须知道确切索引的旁注:使用依赖类型可能会稍微松一些,但这很快就会变得非常复杂。跨度>
  • 函数模板的 ADL 是 C++20 特性。
  • 可以使用std::get,不需要ADL。
  • @evg, @HolyBlackCat 很公平,尽可能使用 ADL 的 std 函数是我的个人偏好,与 OP 的问题无关。我删除了它。
猜你喜欢
  • 2014-08-06
  • 1970-01-01
  • 2013-09-26
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多