Frage Warum ist das kein konstanter Ausdruck?


In diesem trivialen Beispiel test2 Fehler beim Kompilieren obwohl test1 Erfolg, und ich sehe nicht, warum das der Fall ist. Ob arr[i] ist geeignet für einen Rückgabewert von einer markierten Funktion constexpr Warum kann es dann nicht als Template-Argument ohne Typ verwendet werden?

template<char c>
struct t
{ 
    static const char value = c;
};

template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i)
{
    return arr[i];
}

template <unsigned N>
constexpr char test2(const char (&arr)[N], unsigned i)
{
    return t<arr[i]>::value;
}

int main()
{
   char a = test1("Test", 0); //Compiles OK
   char b = test2("Test", 0); //error: non-type template argument 
                              //is not a constant expression
}

Edit: Das macht keinen Unterschied:

template<char c>
struct t
{ 
    static const char value = c;
};

template <unsigned N>
constexpr char test1(const char (&arr)[N])
{
    return arr[0];
}

template <unsigned N>
constexpr char test2(const char (&arr)[N])
{
    return t<arr[0]>::value;
}

int main()
{
   char a = test1("Test"); //Compiles OK
   char b = test2("Test"); //error: non-type template argument 
                           //is not a constant expression
}

16
2017-07-04 21:04


Ursprung


Antworten:


Kurze Antwort: Es gibt keine constexpr Funktionsparameter in C++11/14.

Längere Antwort: test1(), ob i ist keine Kompilierzeitkonstante, die Funktion ist zur Laufzeit noch verwendbar. Aber in test2()kann dem Compiler nicht bekannt sein, ob i ist eine Kompilierzeitkonstante, und dennoch ist es erforderlich, dass die Funktion kompiliert wird.

Z.B. der folgende Code für test1 wird kompilieren

int i = 0;    
char a = test1("Test", i); // OK, runtime invocation of test1()

constexpr int i = 0;
constexpr char a = test1("Test", i); // also OK, compile time invocation of test1()

Lass uns einfach dein sein test2() zu

constexpr char test3(unsigned i)
{
    return t<i>::value;
}

Dies wird nicht kompiliert test3(0) weil drinnen test3()Das kann nicht bewiesen werden i ist ein bedingungslos Kompilierzeitausdruck Du bräuchtest constexpr Funktionsparameter, um das auszudrücken.

Zitat aus dem Standard

5.19 Konstante Ausdrücke [expr.const]

2 Ein bedingter Ausdruck e ist ein Ausdruck einer Kernkonstanten, außer wenn   Auswertung von e nach den Regeln der abstrakten Maschine (1.9),   würde einen der folgenden Ausdrücke auswerten:

- Ein ID-Ausdruck, der sich auf eine Variable oder Datenelement von bezieht   Referenztyp, es sei denn, die Referenz hat eine vorangehende Initialisierung und   entweder
   - Es wird mit einem konstanten Ausdruck oder initialisiert

- Es ist ein nicht-statisches Datenelement eines Objekts, dessen Lebensdauer mit der Auswertung von e begann;

Dieser Abschnitt enthält das folgende Codebeispiel, das Ihrer Frage entspricht:

constexpr int f1(int k) {
    constexpr int x = k; // error: x is not initialized by a
                         // constant expression because lifetime of k
                         // began outside the initializer of x
    return x;
}

weil x Im obigen Beispiel handelt es sich nicht um einen konstanten Ausdruck, dh Sie können Vorlagen nicht mit beiden Instanzen instanziieren x oder k Innerhalb f1.


19
2017-07-04 21:08



Es gibt ein Missverständnis von was constexpr macht das hier. Es zeigt an, dass eine Funktion zur Kompilierzeit für geeignete Argumente auswertbar sein muss, tut dies aber nicht Entfernen Sie im allgemeinen Fall die noch zu kompilierende Anforderung.

Nehmen wir die erste Version:

template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
    return arr[i];
}

Nun, dies ist eindeutig eine Kompilierzeitbewertung:

enum { CompileTimeConstant = test1("Test", 0) };

Ihr Beispiel kann aber, es ist ein Optimierer / QoI-Problem:

char MayBeCompileTimeConstant = test1("Test", 0);

und dieses Beispiel ist offensichtlich nicht, aber ist muss noch auswertbar sein

char arr[10];
int i;
std::cin >> i;
std::cin >> arr;
char b = test1(arr, i);
std::cout << "'" << arr << "'[" << i << "] = " << b << '\n';

Schon seit test2 kann nicht für den letzten Fall kompilieren, es kann überhaupt nicht kompilieren. (Bitte beachten Sie, dass ich nicht vorschlage, dass Code ist gut).


7
2017-07-04 21:32



Das Problem hier ist das Anrufen arr[i] ruft den tiefgestellten Operator hervor operator[]. Dieser Operator gibt keinen konstanten Ausdruck zurück.

Es ist kein Problem von constexpr tatsächlich, ist ein Problem der Vorlage Argumentabzug. Ein Nicht-Typ-Template-Argument muss ein konstanter Ausdruck sein, der das Rückgabeargument des Subscript-Operators nicht ist.

Daher beklagt sich der Compiler zu Recht arr[i] ist kein konstanter Ausdruck.


2
2017-07-04 21:33



weil arr[i]ist kein kompilierbarer konstanter Ausdruck. Es kann zur Laufzeit anders sein.


1
2017-07-04 21:13