Constexpr Aufrufe in Templates



  • Ich spiele aktuell mit Templates und constexpr Funktionen herum. Ich möchte einem Kollegen, welcher auf einem älteren C Standard ist, die möglichen Überprüfungen zur Compile-Zeit zeigen.

    Folgender Code habe ich:

    #include <cstdio>
    #include <format>
    
     constexpr 
     int CountFormatArgs(const std::string_view s)
     {
      int Count = 0;
    
      for (size_t i = 0; i + 1 < s.size(); i += 2)
      {
        if (s[i] == '{' && s[i + 1] == '}')
          Count++;
      }
      return Count;
    }
    
    template<typename T>
    constexpr
    int CountArgs(T t)
    {
      return 1;
    }
    
    template<typename T, typename... Rest>
    constexpr
    int CountArgs(T t, Rest... rest)
    {
      return CountArgs(rest...) + 1;
    }
    
    template<typename... Rest>
    constexpr
    void TestFormatString(const std::string_view s, Rest... rest)
    {
      constexpr int Count_1 = CountFormatArgs(s);
      constexpr int Count_2 = CountArgs(rest...);
    
      static_assert(Count_1 == Count_2, "Anzahl der Parameter stimmt nicht mit Formatstring überein!");
    }
    
    
    int main(int argc, char const* argv[])
    {
      static_assert(CountFormatArgs("{}{}{}") == 3, "CountFormatArgs funktioniert nicht richtig");
      static_assert(CountArgs(1, 2, 'c') == 3, "CountArgs funktioniert nicht richtig");
    
      //TestFormatString("{}{}{}", 1, 2, 'c');
     return 0;
    }
    

    Führe ich den Code aus, so funktioniert dieser. Kommentiere ich jedoch die Zeile TestFormatString wieder ein, so bekomme ich den Fehler "C2131: Der Ausdruck wurde nicht zu einer Konstanten ausgewertet"

    Was mache ich falsch?



  • Du kannst kein static_assert in der Funktion TestFormatString so verwenden, denn die Parameter müssen nicht zwangsläufig Konstanten sein (und damit dürfen auch die beiden Variablen nicht als constexpr deklariert werden). Werfe stattdessen eine Exception!

    Lauffähiger Code

    Fehlerhafter Code (mit Compiler-Fehler!)

    Ansonsten s.a. Cannot use static_assert inside a constexpr function inside a constexpr object.



  • Hi,

    man möge mich gerne korrigieren, aber soweit ich das sehe geht das so nicht (und wie anders weiß ich nicht), da eine constexpr-function auch nicht constexpr ausführbar sein kann; das static_assert aber immer und sicher constexpr sein muss.



  • @Th69 sagte in Constexpr Aufrufe in Templates:

    Werfe stattdessen eine Exception!

    Cool, das funktioniert. Ich habe nun zwei funktionierende Lösungen gefunden:

    template<typename... Rest>
    constexpr
    bool TestFormatString_1(const std::string_view s, Rest... rest)
    {
      //constexpr int Count_1 = CountFormat(s);  // darf ich so nicht machen
      int Count_1 = CountFormat(s);
      int Count_2 = CountArgs(rest...);
    
      return Count_1 == Count_2;
    }
    
    
    template<typename... Rest>
    constexpr
    void TestFormatString_2(const std::string_view s, Rest... rest)
    {
      int Count_1 = CountFormat(s);
      int Count_2 = CountArgs(rest...);
    
      if (Count_1 != Count_2)
        throw std::runtime_error("Anzahl der Parameter stimmt nicht mit Formatstring überein!");
    }
    
    consteval void Test() 
    {
      TestFormatString_2("{}{}{}", 1, 2, 'c');
    }
    
    int main(int argc, char const* argv[])
    {
      static_assert(CountFormat("{}{}{}") == 3, "CountFormat funktioniert nicht richtig");
      static_assert(CountArgs(1, 2, 'c') == 3, "CountArgs funktioniert nicht richtig");
    
      static_assert(TestFormatString_1("{}{}{}", 3, 2, 'c'), "Anzahl der Parameter stimmt nicht mit Formatstring überein!");
    	
      Test();
      return 0;
    }
    

    Ändere ich die Anzahl der Parameter, speichere die Datei ab, so schlägt Visual Studio direkt an. Sehr schön.

    PS:
    Wie schon gesagt das ist nur eine Spielerei.


Anmelden zum Antworten