11

たとえば、 があり、コンパイラstd::arrayを使用して範囲外の要素をインスタンス化しても、constexprエラーは報告されません。

constexpr int EvaluateSpecialArrayIndex(int a)
{ return a * sizeof(int); }

array<int, 5> arr;

cout << arr[98] << endl; //compiles fine

cout << arr[EvaluateSpecialArrayIndex(4)] << endl; //the same as above

これをどうにか制限できないでしょうか?

4

4 に答える 4

16

constexpr関数がコンパイル時に確実に評価されるようにするには、その結果を作成することによって強制する必要がありますconstexpr。例えば:

#include <array>

int
main()
{
    constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
    int i = arr[6];  // run time error
}

でも:

#include <array>

int
main()
{
    constexpr std::array<int, 5> arr{1, 2, 3, 4, 5};
    constexpr int i = arr[6];  // compile time error
}

残念ながら、これが実際に機能するにstd::arrayは、C++11 仕様ではなく、C++14 仕様に準拠する必要があります。C++11 仕様はwithのconstオーバーロードをマークしていないためです。std::array::operator[]constexpr

したがって、C++11 では運が悪いのです。C++14 では、それを機能させることができますがarray、インデックス演算子を呼び出した結果と結果の両方が宣言されている場合に限りconstexprます。

明確化

配列のインデックス付けに関する C++11 の仕様は次のとおりです。

                reference operator[](size_type n);
          const_reference operator[](size_type n) const;

また、配列のインデックス付けに関する C++14 の仕様は次のとおりです。

                reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;

IeがC++14constexprのオーバーロードに追加されました。const

アップデート

また、配列のインデックス付けに関する C++17 の仕様は次のとおりです。

constexpr       reference operator[](size_type n);
constexpr const_reference operator[](size_type n) const;

これでサイクルは完了です。ユニバースはコンパイル時に計算できます。;-)

于 2014-12-19T01:12:14.563 に答える
6

への配列アクセスstd::arrayは、通常の C 配列と同じです。インデックスが有効かどうかを確認することはなく、範囲外の場合は UB を呼び出すだけです。制限が必要な場合は、配列の境界を超える値に対して例外std::array::at()をスローする which を使用します。std::out_of_range()

arr.at(EvaluateSpecialArrayIndex(4)); // terminate called after throwing
                                      // an instance of 'std::out_of_range'

コンパイル時エラーが必要な場合は、次を使用しますstd::get

std::get<EvaluateSpecialArrayIndex(4)>(arr); // error: static_assert failed
                                             // "index is out of bounds"
于 2014-12-19T00:34:57.113 に答える
2

この種のことをチェックするためにstd::array個別のオーバーロードを用意するのは非常にコストがかかるため、簡単な答えです。必要に応じて、コンパイル時定数へのコンパイル チェック済みアクセスを提供するconstexpr独自のラッパーを作成できます。std::array何かのようなもの:

template<typename T, size_t S>
class safeArray
{
    std::array<T, S> m_arr;
    public:
    template<size_t A>
    T& safeAt() { 
        static_assert(A < S, "Index out of bounds");
        return m_arr[A]; 
    }
    // other funcs as needed
};

次に、次のようなことができます。

safeArray<int, 5> arr;
cout << arr.safeAt<98>() << endl; // compile error

ただし、これにより多くの関数が生成される可能性があります。ほとんどの場合、設計が適切であれば、この種のチェックは必要ありません。

于 2014-12-19T00:43:41.607 に答える