Reputation:
I have a situation like this:
#define FOO(Readonly) static_assert(Readonly, "Fire!");
Readonly
will obviously literally pasted as "false" or "true" so the static_assert
will always fire. How do I write a conditional in place of Readonly
so that the static_assert
works properly?
Here is my intended usage:
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y
#define GET_SET(Name, Readonly) decltype(Name) CAT(get, Name)() const { return Name; } \
void CAT(set, Name)(decltype(Name) value = decltype(Name)()) { \
static_assert( /* Insert Magic bullet here */ , #Name " is read-only."); \
Name = value; \
}
class Test
{
int x;
int y;
public:
GET_SET(x, false)
GET_SET(y, true)
};
Example preprocessor output:
decltype(x) getx() const { return x; } void setx(decltype(x) value = decltype(x)()) { static_assert(!false, "x" " is read-only."); x = value; }
decltype(y) gety() const { return y; } void sety(decltype(y) value = decltype(y)()) { static_assert(!true, "y" " is read-only."); y = value; }
Upvotes: 1
Views: 701
Reputation: 24269
The macro directive
#define FOO(Readonly) static_assert(Readonly, "Fire!");
will, as you correctly surmise, forward the value passed into Readonly, so
FOO(false)
will generate
static_assert(false, "Fire!");
Bearing in mind that static_assert
asserts when the condition is false, this will always fire. However
FOO(true);
// generates
static_assert(true, "Fire!");
which will never assert.
In your desired output you wrote:
decltype(x) getx() const { return x; } void setx(decltype(x) value = decltype(x)()) { static_assert(!false, "x" " is read-only."); x = value; }
It appears you just forgot the !
infront of ReadOnly in your macro.
static_assert
is a compile time keyword, it's checked at compile time, not run time, so unless there's some reason it can't be resolved until the template is instantiated (e.g. it's checking against a template-typed member variable or a template parameter) then it's always going to fail at the declaration.
The following code appears to work fine:
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y
#define GET_SET(Name, Readonly) decltype(Name) CAT(get, Name)() const { return Name; } \
void CAT(set, Name)(decltype(Name) value = decltype(Name)()) { \
static_assert( !Readonly , #Name " is read-only."); \
Name = value; \
}
template<typename T>
class Foo
{
int x;
int y;
public:
Foo() : x(0), y(0) {}
GET_SET(x, false);
GET_SET(y, true);
};
Except that, of course, it barfs on the bad case because we've used static_assert
instead of a run-time assert or throw. But it does what you've stated you wanted it to do.
Upvotes: 5