Just having fun with this here ...
My answer requires C++14 and a few external libs, but demonstrates that fairly amazing compile-time computations are available in C++14.
First I need Scott Schurr's str_const
presented at C++ Now 2012. This class is a compile-time string and discussed a bit in this answer.
Then I need this date/time library which is capable of compile-time date and time computations.
Next I need a constexpr
implementation of std::find
:
template <class InputIterator, class T>
constexpr
inline
InputIterator
find(InputIterator first, InputIterator last, const T& value)
{
for (; first != last; ++first)
if (*first == value)
break;
return first;
}
With that I can write str_to_month
which takes a str_const
and turns it into a date::month
:
constexpr
date::month
str_to_month(const str_const& m)
{
constexpr
str_const months[]
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
auto i = ::find(std::begin(months), std::end(months), m);
if (i == std::end(months))
throw std::range_error("str_to_month received out of range argument " +
std::string(m));
return date::month{static_cast<unsigned>(i - std::begin(months)) + 1};
}
Next I need a utility to convert a str_const
into an int
:
constexpr
int
str_to_int(const str_const& s)
{
int r = 0;
auto i = s.begin();
for (; i != s.end() && *i == ' '; ++i)
;
for (; i != s.end(); ++i)
{
r *= 10;
r += *i - '0';
}
return r;
}
(with minimal error checking)
And finally I can use these utilities to turn a str_const
into a date::year_month_day
:
// Assume the form used by __DATE__: Mmm dd yyyy
constexpr
date::year_month_day
str_to_year_month_day(const str_const& s)
{
return str_to_month(s.substr(0, 3))
/str_to_int(s.substr(4, 2))
/str_to_int(s.substr(7));
}
I just exercised all this with the following main
, which computes everything with constexpr
, and confirms the computation with static_assert
:
int
main()
{
constexpr auto ymd = str_to_year_month_day(__DATE__);
using namespace date;
static_assert(ymd == sep/6/2015, "");
constexpr auto ymwd = year_month_weekday{ymd};
static_assert(ymwd == sun[1]/sep/2015, "");
}
I compiled this program on Sep. 6, 2015 which happens to be the first Sunday of this month.
You'll need gcc or clang to do this. Even the latest VS-2015 isn't up to spec with constexpr
enough to do these computations at compile-time.