2017-02-12 1 views
4

Gibt es eine Möglichkeit, auf Indizes, die zur Kompilierzeit und zur Laufzeit bekannt sind, statisch zu bestätigen? Beispiel:static_assert auf Indizes zur Kompilierzeit bekannt

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

danke, aktualisiert die Frage. – sharvey

+0

Sie können __builtin_constant_p für GCC betrachten, aber es wird Ihnen wahrscheinlich keine perfekte Lösung bringen, da es einige wirklich seltsame Verhaltensweisen mit GCC gibt, wenn Sie versuchen, das zu tun, was Sie vorschlagen. –

+0

Ihr 'foo [2]' Zugriff wird nicht im 'constexpr' Kontext gemacht, und Ihr Operator ist auch nicht 'constexpr'. Sie erhalten keinen Fehler bei der Kompilierung. Um Ihr Ziel zu erreichen, verwenden Sie 'assert' (was einen falschen 'consExpr'-Aufruffehler ergibt, wenn falsch) statt' static_assert'. –

Antwort

1

Ich glaube nicht, dass es möglich ist, mit einer einzigen Funktion zu erreichen, was Sie wollen.

Selbst wenn Sie eine constexpr Funktion entwickeln, glaube ich nicht, dass Sie erkennen können, wann die Laufzeit ausgeführt wird und wann die Kompilierzeit ausgeführt wird und wie Sie anders verfahren.

Aber Sie können verschiedene Funktionen entwickeln.

Durch beispielsweise eine Vorlage get<>(), wobei das Template-Argument der Index ist, die nur mit einem Index zur Übersetzungszeit bekannt ist, verwendet werden können, und das kann ein static_assert() zuführen, und ein at(std::size_t) kann, dass ein Index erhalten, berechnet auf Laufzeit mit einer Laufzeitprüfung.

En passant:

1) Ich schlage vor, wie üblich in STL, die Verwendung von at() für einen kontrollierte gebunden Zugang und ein operator[]() für einen gebundenen unkontrollierten Zugang

2) und ich schlage vor, die Verwendung von ein vorzeichenloser Index oder Sie müssen überprüfen, ob der Index >= 0 ist.

Hier finden Sie ein funktionierendes Beispiel

#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

Vielen Dank für diese Antwort, es funktioniert gut. Nur neugierig, wäre es möglich, eine Funktion mit dem Verhalten von "get" und "at" zu schreiben, je nachdem, ob der Indexparameter zur Kompilierzeit bekannt ist? – sharvey

+0

@sharvey - Ich denke nicht, dass es möglich ist; Wenn Sie entdecken, dass das möglich ist, zeigen Sie mir bitte wie. – max66

3

Sie einfach eine Ausnahme oder behaupten werfen könnte. Die Kompilierung wird im Kontext von consExpr fehlschlagen. Dies funktioniert nur, wenn die Bedingung für das Werfen im Kontext von constexpr ausgewertet werden kann. Beachten Sie, dass es in einigen gcc-Versionen einen Fehler gibt, der verhindert, dass der Wurf funktioniert.

Verwandte Themen