【问题标题】:static_assert on indices know at compile time索引上的 static_assert 在编译时就知道
【发布时间】:2017-06-30 21:02:16
【问题描述】:

有没有办法在编译时和运行时断言已知的索引上静态断言?示例:

template <class T, int Dim>
class Foo
{
    T _data[Dim];
    public:
        const T &operator[](int idx) const
        {
            static_assert(idx < Dim, "out of range"); // error C2131: expression did not evaluate to a constant
            return _data[idx];
        }
};

int main()
{
    Foo<float, 2> foo;

    foo[0];
    foo[1];
    foo[2]; // compiler error

    for (int i=0; i<5; ++i)
    {
        foo[i]; // run time assert when i > 1
    }

    return 0;
}

【问题讨论】:

  • 谢谢,更新了问题。
  • 您可以查看 GCC 的 __builtin_constant_p,但它可能不会为您提供完美的解决方案,因为当您尝试执行您的建议时,GCC 会出现一些非常奇怪的行为。跨度>
  • 您的foo[2] 访问未在constexpr 上下文中完成,您的操作员也不是constexpr。您不会收到编译时错误。要实现您的目标,请使用assert(如果为 false,将给出非constexpr 调用错误)而不是static_assert

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


【解决方案1】:

我认为用一个函数不可能得到你想要的。

即使您开发了constexpr 函数,我认为您也无法检测到何时在运行时执行以及何时在编译时执行并以不同的方式进行操作。

但你可以开发不同的功能。

例如,模板get&lt;&gt;(),其中模板参数是索引,只能与编译时已知的索引一起使用,并且可以执行static_assert()at(std::size_t),可以通过运行时检查接收在运行时计算的索引。

过路人:

1) 我建议,像往常一样在 STL 中,使用at() 进行绑定检查访问,使用operator[]() 进行绑定未检查访问

2) 我建议使用无符号索引,否则您必须检查索引是否为&gt;= 0

以下是一个工作示例

#include <iostream>
#include <stdexcept>

template <class T, std::size_t Dim>
class Foo
 {
   private:
      T _data[Dim];

   public:
      T const & operator[] (std::size_t idx) const
       { return _data[idx]; }

      template <std::size_t IDX>
      T const & get () const
       {
         static_assert(IDX < Dim, "out of range");

         return this->operator[](IDX);
       }

      T const & at (std::size_t idx) const
       {
         if ( idx >= Dim )
            throw std::range_error("out of range");

         return this->operator[](idx);
       }
 };

int main ()
 {
   Foo<float, 2U> foo;

   foo.get<0U>();
   foo.get<1U>();
   //foo.get<2U>(); // compiler error

   for ( auto i = 0U ; i < 5U ; ++i )
      foo.at(i); // run time exception when i > 1

   return 0;
 }

【讨论】:

  • 谢谢你的回答,它工作得很好。只是好奇,是否可以编写一个具有getat 行为的函数,这取决于在编译时是否知道索引参数?
  • @sharvey - 我不认为这是可能的;如果你发现可以做到,请告诉我怎么做。
【解决方案2】:

您可以简单地抛出异常或断言。它将在 constexpr 上下文中编译失败。这仅在可以在 constexpr 上下文中评估抛出条件时才有效。 请注意,某些版本的 gcc 中存在一个错误,导致 throw 无法正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-26
    • 2012-11-30
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多