2015-07-29 1 views
12

Je bourrais quelques valeurs dans un constexpr std::array et puis continuant la qualité statique de la compilation dans plus de constexpr valeurs lorsque j'ai découvert que vous ne pouvez pas utiliser un élément en tant qu'initialisateur constexpr dans C++ 11.Pourquoi l'opérateur [] d'un std :: array n'est-il pas constexpr temporaire?

C'est parce que std::array::operator[] est en réalité pas marqué constexpr jusqu'à C++ 14: https://stackoverflow.com/a/26741152/688724

Après une mise à jour du drapeau du compilateur, je peux maintenant utiliser un élément d'un constexpr std::array comme valeur constexpr:

#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 

Mais parfois, je veux utiliser un tableau temporaire dans un calcul constexpr, et cela ne fonctionne pas.

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

Je reçois ce billet depuis clang 3.6 ++ avec 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. 

Quelle est la différence entre les deux variables j'indexations? Pourquoi ne puis-je pas utiliser un std::arrayoperator[] comme constexpr?

Répondre

6

Le array temporaire dans votre deuxième exemple est lui-même pas const, vous finissez par appeler la surcharge non constoperator[], ce qui est constexpr. Vous pouvez obtenir votre code pour travailler si vous commencez à convertir le array en const.

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

Live demo

+0

Oh, bien sûr! J'ai besoin de jouer avec cela un peu plus, mais voyez-vous une raison pour laquelle l'opérateur non-const [] 'ne devrait pas aussi être marqué' constexpr'? Oui, il renvoie une référence non ''const' mais si je comprends bien, [la relaxation de la règle C++ 14] (https://isocpp.org/wiki/faq/cpp14-language#extended-constexpr) sépare la compilation calcul de temps de cv-qualification. Y aurait-il des effets secondaires? 'opérateur de référence constexpr [] (type_type n); constexpr const_reference operator [] (type_type n) const; ' –

+0

Cela semble fonctionner correctement: [Démo en direct] (http: //coliru.stacked-crooked.com/a/ab5856b0809e308c) –

+0

@XoWang Je ne suis pas sûr de ce que les ramifications de faire ce serait. Il semble que tous les ajouts C++ 14 'constexpr' aux fonctions membres dans la bibliothèque standard ont été appliqués uniquement aux surcharges' const', donc l'intention semble être que ces fonctions ne doivent pas muter les membres de données, mais encore une fois, je Je ne sais pas pourquoi. – Praetorian

1

Je crois que vous ne pouvez pas utiliser le second parce que, contrairement à la première array, l » operator []array le second est pas lui-même un constexpr si vous essayez d'initialiser b avec une valeur d'exécution.

3

alternative à @ solution de contournement de prétorienne, vous pouvez utiliser 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! 
} 

Je pense que std::get est plus "agressif" que operator[] dans la production d'un constexpr.

(testé avec clang 3.5 et gcc 5.0 C++ 14, devrait fonctionner avec C++ 11)

En outre, pour une raison quelconque (lié au paramètre du modèle), ADL ne fonctionne pas ici, il est donc pas possible d'écrire simplement get<0>(std::array<int, 1>{{3}}).