I have the following declaration -
constexpr unsigned int compileYear = (__DATE__[7] - '0') * 1000 + (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0');
Using Visual Studio 2022 and C++ 20, this function cannot compile:
constexpr std::string get_compilation_year()
{
return std::to_string(compileYear); // cannot result in a constant expression
}
And for some reason, adding an empty string to it, makes it compile successfully:
constexpr std::string get_compilation_year()
{
return std::to_string(compileYear) + ""; // OK, it works
}
I want to understand the reason for that behavior of the compiler.
std::to_string(int)
is not constexpr
so you will not be able to initialize a constexpr
variable via a call to get_compilation_year()
even if it compiles in its current state.
You could use one of the constexpr
std::string
constructors instead:
template< class InputIt >
constexpr std::string(InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
or
constexpr std::string(std::initializer_list<char> ilist,
const Allocator& alloc = Allocator() );
Currently, only the one that takes an std::initializer_list<char>
works in this context in MSVC, gcc and clang. Clang doesn't like the iterator version (yet).
So, a (somewhat) portable C++20 version could look like this:
constexpr std::string get_compilation_year() {
return {__DATE__[7], __DATE__[8], __DATE__[9], __DATE__[10]};
}
Or as suggested by Pepijn Kramer, make it a std::string_view
instead:
constexpr std::string_view get_compilation_year() {
return {__DATE__ + 7, 4};
}
The somewhat portable version works as long as there's no allocation made by the constructor. For a longer text including the current year, you could initialize a std::array
and create a std::string_view
over it:
#include <array>
#include <string_view>
#include <utility>
constinit auto copyright_data = [] {
auto& beg = "Copyright (C) XXXXX 1986 - ";
return [&]<std::size_t... I>(std::index_sequence<I...>) {
return std::array{beg[I]..., __DATE__[7], __DATE__[8], __DATE__[9],
__DATE__[10]};
}(std::make_index_sequence<sizeof(beg) - 1>{});
}();
constexpr std::string_view copyright_text{copyright_data.begin(),
copyright_data.end()};