2017-02-12 44 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中存在一個防止拋出工作的錯誤。

相關問題