Why doesn’t constexpr function returning std::string doesn’t compile when outside templated class?

Note: I am using gcc, but tested on godbolt.org and it also works on msvc, but not on clang

I accidentally discovered that the following simple function compiles while being in a templated class, but not as a free function. Could someone explain why?

Compiles OK:

   template <typename T = void>
   class A
      static constexpr std::string f()
         return std::string();

Doesn’t compile:

    constexpr std::string f()
        return std::string();

Throws error:

error: invalid return type ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} of ‘constexpr’ function ...
/usr/include/c++/9/bits/basic_string.h:77:11: note: ‘std::__cxx11::basic_string<char>’ is not literal because:
   77 |     class basic_string
      |           ^~~~~~~~~~~~
/usr/include/c++/9/bits/basic_string.h:77:11: note:   ‘std::__cxx11::basic_string<char>’ has a non-trivial destructor


std::string is supposed to be a literal type in C++20. However, it seems that GCC hasn’t implemented this new feature yet, so it cannot accept std::string as the return type of a constexpr function.

However, when the constexpr function is part of a template, it doesn’t exist as a function until it’s instantiated. A class template is a blueprint for a class; it’s not itself a class. When the class template is instantiated, then its set of members will come into being. So in your first example, what you have is a class template that will always produce ill-formed instantiations, because A<T>::f will always have an invalid return type. When this occurs, the program is “ill-formed, no diagnostic required”, which means that the program is ill-formed, but the compiler is not required to tell you that the program is ill-formed. If the compiler accepts the program, the result of running the program is undefined.