2017-02-12 45 views
4

有没有一种方法可以在编译时已知的索引上静态声明并且在运行时断言?例如:在编译时知道索引上的static_assert

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; 
} 
+0

谢谢,更新了这个问题。 – sharvey

+0

你可以看看__builtin_constant_p为GCC,但它不可能为你提供一个完美的解决方案,因为当你尝试做你所建议的事情时,有一些非常奇怪的GCC行为。 –

+0

你的'foo [2]'访问不是在'constexpr'上下文中完成的,你的操作符也不是'constexpr'。你不会得到编译时错误。为了实现你的目标,使用'assert'(这将给出一个非''textexpr'调用错误,如果为false)而不是'static_assert'。 –

回答

1

我不认为这是可能的获得你想要什么与一个单一的功能。

即使你开发了一个constexpr函数,我不认为你能够检测何时执行运行时,何时执行编译时间并以不同的方式行事。

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

例如,模板get<>(),其中模板参数是指数,只能用在编译时已知的指标来使用,并且可以执行static_assert()at(std::size_t),能够接收在计算的索引运行时间与运行时间检查。

顺便:

1)建议,如在STL通常,对于一个结合使用at()检查连接和operator[]()一个绑定未检查的访问

2)和我建议使用一个无符号的索引或者你必须检查索引是>= 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; 
} 
+0

谢谢你的回答,它工作得很好。只是好奇,是否有可能编写一个函数的行为是'get'和'at',这取决于在编译时是否已知索引参数? – sharvey

+0

@sharvey - 我不认为这是可能的;如果你发现可以完成,请告诉我如何。 – max66

3

你可以简单地抛出一个异常或断言。它将在编译环境下编译失败。这只适用于如果可以在constexpr上下文中评估投掷条件的情况。 请注意,在某些版本的gcc中存在一个防止抛出工作的错误。

相关问题