case1:
#include <string>
inline constexpr std::string test(std::string s) noexcept
{
return s "xxx";
}
int main()
{
auto s = test("abc");
}
c 20 with gcc 12.1 is built okay, c 17 with gcc 12.1 or c 20/17 with gcc 11.1 was failed,
constexpr std::string
, Is this a new feature, or what does this mean?
case2:
#include <string>
int main()
{
constexpr std::string test{"xxxxxx"};
}
And in this case both failed, what is the difference between these two cases.
CodePudding user response:
The following might not compile either, for you:
constexpr auto s = test("abc");
There's a slight semantical difference between a constexpr
object and a constexpr
function.
A constexpr
object must be a compile-time constant.
A constexpr
function might be a compile-time constant if everything in the function is a constant expression. Subsequently, the result of the function is a constant expression if its parameters are, and obviously not if they're not.
What appears to be happening is that your compiler hasn't yet implemented the constexpr
version of the std::string
constructor in C 20, but has implemented the constexpr
operator.
Hence the function gets compiled without a constant expression as its parameter, but since its result is not assigned to a constexpr
object this is not immediately apparent.
But assigning the function's result to a constexpr
reveals the ugly truth.
CodePudding user response:
There are two different use cases of constexpr
here:
constexpr
functionsconstexpr
objects
When you see it on a function such as
inline constexpr std::string test(std::string s) noexcept
{
return s "xxx";
}
the constexpr
is not part of the return type, in the same way that inline
is not part of the return type; it is part of the function definition. In this case, constexpr
says "this function can possibly be run at compile time".
The second use case you've mentioned is tagging an object definition as constexpr
. In this use case, you're telling the compiler that this must be a compile time constant, and currently std::string
objects cannot be marked constexpr
due to the dynamic memory allocation that it does which it performed at runtime.
One thing you may have seen is that the std::string
constructor was marked constexpr
in C 20. This does not mean that you can create constexpr
instances of std::string
. It just means that std::string
can be constructed and used within constexpr
contexts (like a constexpr
function).
You may then ask "if std::string
requires runtime allocation, how can it be used within a constexpr
function?". The basic answer is that the compiler uses a different allocation strategy to enable it, and does extra magic to make sure no undefined behaviour occurs. You can see more info here.
To give a bit more information about constexpr
functions, note that I said it could "possibly" be run at compile time. A function marked constexpr
can be run at either compile time or runtime, depending on the arguments it's called with
constexpr int double_val(int x) { return 2 * x; }
int main() {
const int y = double_val(4); // likely ran at compile time
int input = 0;
std::cin >> input;
const int z = double_val(input); // run at runtime
}
If you want to force the function to only run at compile time, that's what C 20's consteval
keyword allows you to do.
consteval int double_val(int x) { return 2 * x; }
int main() {
const int y = double_val(4); // fine, ran at compile time
int input = 0;
std::cin >> input;
const int z = double_val(input); // ERROR, could not compile
}