简体   繁体   中英

Using a static_assert in a macro

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; }

Live Example

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 (eg 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);
};

http://ideone.com/BkRYBE

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM