Aufruf von constexpr im Standard-Template-Argument

Lesezeit: 4 Minuten

Aufruf von constexpr im Standard Template Argument
cschwan

In C++11 verwende ich eine constexpr-Funktion als Standardwert für einen Vorlagenparameter – sie sieht so aus:

template <int value>
struct bar
{
    static constexpr int get()
    {
        return value;
    }
};

template <typename A, int value = A::get()>
struct foo
{
};

int main()
{
    typedef foo<bar<0>> type;

    return 0;
}

G++ 4.5 und 4.7 kompilieren dies, Clang++ 3.1 jedoch nicht. Die Fehlermeldung von clang lautet:

clang_test.cpp:10:35: error: non-type template argument is not a constant expression
template <typename A, int value = A::get()>
                                  ^~~~~~~~
clang_test.cpp:17:19: note: while checking a default template argument used here
        typedef foo<bar<3>> type;
                ~~~~~~~~~^~
clang_test.cpp:10:35: note: undefined function 'get' cannot be used in a constant expression
template <typename A, int value = A::get()>
                                  ^
clang_test.cpp:4:23: note: declared here
        static constexpr int get()
                             ^
1 error generated.

Was ist richtig?

  • Ich habe das gleiche Problem mit Clang 3.1. Irgendwelche Ideen, wie man das umgehen kann? Muss ich anstelle eines constexpr die Template-Metaprogrammierung verwenden, um es in einer Template-Instanziierung “aufzurufen”?

    – Gurgeh

    12. November ’12 um 16:25

Aufruf von constexpr im Standard Template Argument
Johannes Schaub – litb

Richard Smith (zygoloid) vom LLVM IRC-Kanal hatte ein kurzes Gespräch mit mir über dieses Thema, das Ihre Antwort ist

<litb> hello folks
<litb> zygoloid, what should happen in this case?
<litb> http://stackoverflow.com/questions/10721130/calling-constexpr-in-default-template-argument
<litb> it seems to be clang's behavior is surprising
<litb> zygoloid, i cannot apply the "point of instantiation" rule to constexpr 
  function templates. if i call such a function template, the called definition's 
  POI often is *after* the specialization reference, which means at the point of 
  the call, the constexpr function template specialization is "undefined".
<zygoloid> it's a horrible mess. Clang does not do what the standard intends, but 
  as you note, the actual spec is gloriously unclear
<d0k> :(
<zygoloid> we should instantiate bar<3>::get(), because it is odr-used, but we 
  don't, because we incorrectly believe it's used in an unevaluated context
<zygoloid> conversely, the point of instantiation is too late :/
<zygoloid> PR11851

Es scheint also, dass Clang manchmal aufgerufene Funktions-Templates oder Member-Funktionen von Klassen-Templates instanziiert, aber ihre Instanziierung ist zu spät für den Aufruf, und in anderen Fällen instanziiert es sie nicht einmal, weil es denkt, dass es sie nie brauchen wird (unbewertet). Kontext).

  • Für diejenigen, die die Entwicklung verfolgen möchten, schauen Sie sich den Bugzilla-Eintrag unter an llvm.org/bugs/show_bug.cgi?id=11851

    – cschwan

    24. Mai ’12 um 11:41

  • Dies sollte nun behoben sein.

    – Edward Kmett

    11. September ’16 um 11:17

1641828623 728 Aufruf von constexpr im Standard Template Argument
smerlin

Ich denke GCC Klingeln ist richtig

zitiert aus n3290:

14.3.2 Nicht-Typ-Argumente der Vorlage [temp.arg.nontype]

  1. Ein Template-Argument für einen Nicht-Typ, Nicht-Template-Template-Parameter muss eines der folgenden sein:
    • für einen typfreien Schablonenparameter vom Ganzzahl- oder Aufzählungstyp ein umgewandelter > konstanter Ausdruck (5.19) des Typs des Schablonenparameters; oder

BEARBEITEN: 5.19 3

Ein konstanter Literalausdruck ist ein konstanter Prvalue-Kernausdruck vom Literaltyp, aber nicht vom Zeigertyp. Ein ganzzahliger konstanter Ausdruck ist ein literaler konstanter Ausdruck des ganzzahligen oder bereichslosen Aufzählungstyps. [ Note: Such expressions may be used as array bounds (8.3.4,
5.3.4), as bit-field lengths (9.6), as enumerator initializers if the underlying type is not fixed (7.2), as null pointer constants (4.10),
and as alignments (7.6.2). —end note ] Ein konvertierter konstanter Ausdruck vom Typ T ist ein literaler konstanter Ausdruck, der implizit in den Typ T konvertiert wird, wobei die implizite Konvertierung (sofern vorhanden) in einem literalen konstanten Ausdruck zulässig ist und die implizite Konvertierungssequenz nur benutzerdefinierte Konvertierungen enthält, lvalue-to- rvalue-Conversions (4.1), integrale Werbeaktionen (4.5) und integrale Conversions (4.7) außer einschränkende Conversions (8.5.4).

[ Note: such expressions may be used as case expressions (6.4.2), as enumerator initializers if the underlying type is fixed (7.2), and as integral or enumeration non-type template arguments (14.3). —end note ]

  • @cschwan: Entschuldigung, ich habe mich geirrt, habe nicht alles von 5.19 gelesen. Clang ist korrekt, siehe meine Bearbeitung.

    – smerlin

    23. Mai ’12 um 14:07

  • Ok, hilf mir ein bisschen: In meinem Fall der Standardwert für value muss ein “konvertierter konstanter Ausdruck” sein. 5.19.3 besagt nun, dass A::get() ist kein konstanter Ausdruck, weil es keines der darin aufgeführten Elemente ist, oder?

    – cschwan

    23. Mai ’12 um 14:28

  • A::get() ist ein core constant expresion (beschrieben in 5.19.2), aber nicht a converted constant expression

    – smerlin

    23. Mai ’12 um 15:12


  • Warum ist es kein konvertierter konstanter Ausdruck?

    – Johannes Schaub – litb

    23. Mai ’12 um 19:46

  • Ein konstanter Literalausdruck ist ein konstanter Prvalue-Kernausdruck vom Literaltyp, der kein Zeiger ist. Da stimmst du schon zu A::get() ist ein zentraler konstanter Ausdruck, und da es meiner Meinung nach kein Argument dafür gibt, dass es sich um einen prvalue vom Literal-Nicht-Zeiger-Typ handelt, A::get() ist ein wörtlicher konstanter Ausdruck. Ein konstanter Literalausdruck ohne implizite Konvertierungen ist gemäß dem von Ihnen zitierten Text auch ein konvertierter konstanter Ausdruck. Verpasse ich etwas?

    Benutzer743382

    23. Mai ’12 um 22:16

.

313420cookie-checkAufruf von constexpr im Standard-Template-Argument

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy