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
{
public:
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
CodePudding user response:
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.