5 Replies Latest reply on May 17, 2018 9:25 AM by Maxim Kartashev-Oracle

    Constexpr inherited constructor fails when initializing constexpr array

    koval

      Calling inherited constexpr constructor compiles fine with normal initialization but fails when constructing array:

      #include <cstddef>
      
      class StringRef {
          const char* str;
          size_t len;
      public:
          constexpr StringRef(const char* s, size_t l): str{s}, len{l} { }
      };
      
      class StringLiteral: public StringRef {
      public:
          template<size_t N>
          constexpr StringLiteral(const char (&str)[N]): StringRef{str, N-1}
          {
          }
      };
      
      constexpr StringLiteral ok("abcd");  // this works fine
      constexpr StringLiteral fail[] = {"abcd"};  // the error comes from here
      
      

      CC -std=c++14 test.cpp

      "test.cpp", line 13: Error: Cannot use unsigned long to initialize const char*.

      1 Error(s) detected.

      Studio 12.5 compiles this example fine

       

      Also it seems that 12.6 compiles without errors if fail[] is not constexpr

        • 1. Re: Constexpr inherited constructor fails when initializing constexpr array
          Maxim Kartashev-Oracle

          Thanks for reporting the problem, I filed a new bug for you - 27313895. If you have a support contract, you can escalate for a patch.

          1 person found this helpful
          • 2. Re: Constexpr inherited constructor fails when initializing constexpr array
            Oqelu

            When a struct in the array has more than 1 member, and you try different initializer lists, CC reports more of various errors, which cannot be true just like what you report. Examples:

            • If quantity of members in {initializer list} differs from quantity of members of the struct, CC can't find a function constructor({initializer list}). Although, default, implicit constructor must be present.
            • Can't use second parameter to initialize the first member of a struct. Although, it is second, not first.

            This may be 1 more bug.

            Workaround: remove constexpr, or replace it with simple const.

            Why at all use constexpr?

            • 3. Re: Constexpr inherited constructor fails when initializing constexpr array
              koval

              constexpr allows pre-computing static initializers at compile time without the need to write external code generators.

              Imagine e.g. building a regex automaton or hash tables which are stored directly in data section. If you need to put your program in ROM, you have no option of filling that memory at run time. You have to generate initializers with a separate tool but that keeps part of the program logic somewhere else. If that logic is expected to match run-time versions (like with hash functions) keeping everything in sync increases maintenance costs and is error-prone

              • 4. Re: Constexpr inherited constructor fails when initializing constexpr array
                Oqelu

                Do you mean that const puts a variable somewhere else, rather than in "data section"?

                Usually a compiler decides where to store data: in code as literals, in "data section", or anywhere else. It also decides which addresses are code (possibly Flash), ROM.
                You take control over this with pragma.

                What constexpr does differently from const?
                And why const would not work in your case?

                It seems that makers of compiler CC do not understand the meaning of constexpr too.
                If I remember well, its code is a clumsy template, instead of real "built-in".
                Preprocessor directive #if fails to accept variables declared as constexpr.
                If I remember well, static_assert fails to accept it too.

                • 5. Re: Constexpr inherited constructor fails when initializing constexpr array
                  Maxim Kartashev-Oracle

                  Preprocessor directive #if fails to accept variables declared as constexpr.

                  I'm not exactly sure what do you mean by "accept variables" (an example would help), but if it's something like this, the compiler's correct:

                  constexpr int i = 42;
                  #if i == 42
                  // OK
                  #else
                  #error "I don't understand constexpr"
                  #endif
                  

                  You can see for yourself what other compilers do. The thing is, the C++ standard defines 9 phases of translation, each starting when the previous one has completely finished; preprocessing directives are executed at phase 4, while constexpr variables are only recognized at 7. See 5.2 [lex.phases] in the latest draft, for example.

                  If I remember well, static_assert fails to accept it too.

                  Since static_assert is not a preprocessor directive, constexprs should work. For example,

                  constexpr int i = 42;
                  static_assert(i != 42, "hey!");
                  

                   

                  $ CC -std=c++14 a.cc

                  "a.cc", line 2: Error: Static assertion failed: hey!.

                  1 Error(s) detected.