2015-07-29 38 views
12

Wypychałem niektóre wartości do , a następnie kontynuując dobro statyczne w czasie kompilacji do większej liczby wartości constexpr, gdy odkryłem, że nie można użyć elementu jako inicjalizatora constexpr w C++ 11.Dlaczego operator [] nie jest tymczasowym constexpr std :: tablica?

To dlatego std::array::operator[] faktycznie nie zaznaczono constexpr aż C++ 14: https://stackoverflow.com/a/26741152/688724

Po uaktualnieniu flag kompilatora, mogę teraz zastosować element o constexpr std::array jako constexpr wartość:

#include <array> 

constexpr std::array<int, 1> array{{3}}; 
// Initialize a constexpr from an array member through its const operator[] 
// that (maybe?) returns a const int & and is constexpr 
constexpr int a = array[0]; // Works in >=C++14 but not in C++11 

Ale czasami chcę użyć tymczasowej tablicy w obliczeniach constexpr, a to nie działa.

// Initialize a constexpr from a temporary 
constexpr int b = std::array<int, 1>{{3}}[0]; // Doesn't work! 

uzyskać to od Clang ++ 3.6 z -std = C++ 14:

prog.cc:9:15: error: constexpr variable 'b' must be initialized by a constant expression 
constexpr int b = std::array<int, 1>{{3}}[0]; // Doesn't work! 
      ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~ 
prog.cc:9:19: note: non-constexpr function 'operator[]' cannot be used in a constant expression 
constexpr int b = std::array<int, 1>{{3}}[0]; // Doesn't work! 
       ^
/usr/local/libcxx-3.5/include/c++/v1/array:183:41: note: declared here 
    _LIBCPP_INLINE_VISIBILITY reference operator[](size_type __n)    {return __elems_[__n];} 
             ^
1 error generated. 

Jaka jest różnica między tymi dwoma zmiennymi mam Indeksowanie w? Dlaczego nie mogę użyć tymczasowo zainicjowanego tymczasowo: operator[]operator[] jako constexpr?

Odpowiedz

6

Tymczasowy array w drugim przykładzie to sobie nie const, więc kończy się wywołaniem nieprzestrzegania constoperator[] przeciążenia, co nie jest constexpr. Możesz uruchomić swój kod, jeśli najpierw odrzucisz array do const.

constexpr int b = static_cast<std::array<int, 1> const&>(std::array<int, 1>{{3}})[0]; 

Live demo

+0

Och, oczywiście! Muszę się z tym trochę pogodzić, ale czy widzisz jakiś powód, dla którego niestanowiący operatora '[]' nie powinien być również oznaczony 'constexpr'? Tak, zwraca referencję inną niż 'constst', ale jak rozumiem, rozluźnienie reguły C++ 14 (https://isocpp.org/wiki/faq/cpp14-language#extended-constexpr) oddziela kompilację Obliczanie czasu z kwalifikacji cv. Czy wystąpią jakieś skutki uboczne tego? 'operator referencji constexpr [] (typ_ wielkości_ n); constexpr const_reference operator [] (size_type n) const; ' –

+0

Wydaje się działać poprawnie: [Live demo] (http: //coliru.stacked-crooked.com/a/ab5856b0809e308c) –

+0

@XoWang Nie jestem pewien, jakie byłyby tego konsekwencje. Wygląda na to, że wszystkie dodatki 'constexpr' w C++ 14 do funkcji składowych w bibliotece standardowej zostały zastosowane tylko do przeciążeń' const', więc wydaje się, że te funkcje nie powinny zmutować elementów danych, ale znowu, I nie znam przyczyny. – Praetorian

1

Uważam, że nie można użyć drugiego array „s operator [] ponieważ, w przeciwieństwie do pierwszego array, drugi nie jest sama w sobie constexpr więc starasz się zainicjować b o wartości wykonawczego.

3

Alternatywnie do @ obejście pretorianów, można użyć std::get(std::array)

#include<array> 
int main(){ 
    constexpr int b = 
    // std::array<int, 1>{{3}}[0]; // Doesn't work! 
    // static_cast<std::array<int, 1> const&>(std::array<int, 1>{{3}})[0]; // long but Works! 
     std::get<0>(std::array<int, 1>{{3}});// Works! 
} 

myślę std::get jest bardziej "agresywna" niż operator[] w produkcji constexpr.

(Testowane z clang 3.5 i gcc 5.0 C++ 14, powinien współpracować z C++ 11)

Również z jakiegoś powodu (związane z parametrem szablonu), ADL tu nie pracuje, więc jest nie można po prostu napisać get<0>(std::array<int, 1>{{3}}).