コンパイル時に現在の月のインデックスを取得する

最初:コンパイル時にこれが必要ですか?実行時間が許容できる場合は簡単です:http://www.keil.com/support/docs/1102.htm

しかし、正気から離れて、コンパイル時の楽しみを持ちましょう!

ここではテンプレートを使用していますが、実際には必要ありません。代わりに大規模な運命の表現を使用できます:

static const char c0 = __DATE__[0];
static const char c1 = __DATE__[1];
static const char c2 = __DATE__[2];
static const unsigned int month = (
    c0 == 'J' // Jan Jun Jul
        ? (c1 == 'a' ? 1 : (c2 == 'n' ? 6 : 7))
    : c0 == 'F' ? 2
    : c0 == 'M' // Mar May
        ? (c2 == 'r' ? 3 : 5)
    : c0 == 'A' // Apr Aug
        ? (c1 == 'p' ? 4 : 8)
    : c0 == 'S' ? 9
    : c0 == 'O' ? 10
    : c0 == 'N' ? 11
    : 12
);

免責事項:私は頭のてっぺんからそれを書きました。今はうまくいきますが、3 月を間違えたのかもしれません。

実際、もっと楽しみたい*場合は、いくつかの文字で算術演算を使用できます:

static const char c0 = __DATE__[0];
static const char c1 = __DATE__[1];
static const char c2 = __DATE__[2];
static const unsigned int month = (
    c0 == 'J' // Jan Jun Jul
        ? (c1 == 'a' ? 1 : (c2 == 'n' ? 6 : 7))
    : c0 == 'M' // Mar May
        ? (3 + (c2 == 'y') * 2)
    : c0 == 'A' // Apr Aug
        ? (4 + (c1 == 'u') * 4)
    : c0 == 'S' ? 9
    : c0 <= 'F' ? (12 - (c0 - 'D') * 5) // Feb, Dec
    : (11 + 'N' - c0) // Oct, Nov
);

*:「楽しい」という意味:他の開発者に嫌われている

これらは const であるため、テンプレートで使用できます。たとえば、11 月に終了する契約の仕事があり、それが終わったら、数日間高レートで確実に戻ってくるようにしたいとします。

#include <iostream>
using namespace std;

static const unsigned int month = ...;

template <int n> class mm {
public:
    static int v;
};

template<> int mm<9>::v=3; // still employed
template<> int mm<10>::v=2; // let's not be too suspicious
template<> int mm<11>::v=1; // patience...
// no value for December - boom! we're in the money! Just in time for Christmas!

int main() {
    std::cout << mm<month>::v;
    return 0;
}

最後に、グローバル スコープを散らかしたくない場合は、constexpr 関数を使用する必要があります。

static constexpr int getMonth( void ) {
    const char c0 = __DATE__[0];
    const char c1 = __DATE__[1];
    const char c2 = __DATE__[2];
    return (
        c0 == 'J' // Jan Jun Jul
            ? (c1 == 'a' ? 1 : (c2 == 'n' ? 6 : 7))
        : c0 == 'F' ? 2
        : c0 == 'M' // Mar May
            ? (c2 == 'r' ? 3 : 5)
        : c0 == 'A' // Apr Aug
            ? (c1 == 'p' ? 4 : 8)
        : c0 == 'S' ? 9
        : c0 == 'O' ? 10
        : c0 == 'N' ? 11
        : 12
    );
}

...

std::cout << mm<getMonth()>::v;

ここでこれを楽しんでください...

私の回答には C++14 といくつかの外部ライブラリが必要ですが、C++14 ではかなり驚くべきコンパイル時の計算が可能であることを示しています。

まず、Scott Schurr の str_const が必要です C++ Now 2012 で発表されました。このクラスはコンパイル時の文字列であり、この回答で少し説明されています。

次に、コンパイル時に日付と時刻を計算できるこの日付/時刻ライブラリが必要です。

次は constexpr が必要です 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;
}

これで str_to_month と書くことができます str_const かかります 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};
}

次に str_const を変換するユーティリティが必要です 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;
}

(最小限のエラー チェックあり)

そして最後に、これらのユーティリティを使用して str_const を有効にすることができます 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));
}

次の main でこれらすべてを実行しました 、 constexpr ですべてを計算します 、および 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, "");
}

私はこのプログラムを 2015 年 9 月 6 日、たまたま今月の最初の日曜日にコンパイルしました。

これを行うには gcc または clang が必要です。最新の VS-2015 でさえ constexpr の仕様に達していません コンパイル時にこれらの計算を行うのに十分です.