I'm trying to convert month from __DATE__
in format Mmm
to number in compile time. I need it for gcc and MS VC 2012.
my attempt:
template <char C0, char C1, char C2>
struct month{};
template<> struct month < 'J', 'a', 'n'> { static const unsigned id = 1; };
template<> struct month < 'S', 'e', 'p'> { static const unsigned id = 9; };
static const char c0 = __DATE__[0];
static const char c1 = __DATE__[1];
static const char c2 = __DATE__[2];
static const unsigned currId = month<c0, c1, c2>::id; //this gives error
static const unsigned currId2 = month<'S', 'e', 'p'>::id; //this is fine
gives in MS VC
error C2970: 'month' : template parameter 'C0' : 'c0' : an expression involving objects with internal linkage cannot be used as a non-type argument
but on ideone works fine.
Is there a way to make this work cross platform/compiler?
edit
I need a compile-time constant
So answers in similar question doesn't really help. I need to for example subtract two dates (current and some date in code) and give compile time error when difference between those two is large enough.
First: are you sure you need this at compile-time? If run-time is acceptable it's easy: http://www.keil.com/support/docs/1102.htm
But moving away from what's sane, let's have some compile-time fun!
You're using templates here but you really don't need to. You can use a massive expression of doom instead:
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
);
Disclaimer: I just wrote that off the top of my head. It works now, but who knows, maybe I got March wrong.
In fact if you want to get even more fun* we can use arithmetic on some characters:
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
);
*: by "fun" I mean: hated by other developers
Since these are const, you can then use it with templates. For example, suppose we've got a contract job which ends in November, and we want to be sure we'll get brought back in for a few days at a high rate once it's over:
#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;
}
Finally, if you don't want to be littering the global scope, you should use a constexpr function:
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With