constexpr替换宏而不回归

Ale*_*k86 1 c++ macros compile-time constexpr

在我们公司的代码中我们使用64位标志枚举:

enum Flags : unsigned long long {
    Flag1 =  1uLL<<0, // 1
    //...
    Flag40 = 1uLL<<40 // 1099511627776
};
Run Code Online (Sandbox Code Playgroud)

并添加注释以查看每个标志十进制值,即使我们在文本查看器中读取代码.问题是没有什么能阻止开发人员在评论中输入错误的数字.

有一个解决这个问题的方法 - 一个带有static_assert +宏的模板可以轻松使用这种方法 - 无需使用括号并在所有地方添加:: val:

template <unsigned long long i, unsigned long long j>
struct SNChecker{
    static_assert(i == j, "Numbers not same!");
    static const unsigned long long val = i;
};

#define SAMENUM(i, j) SNChecker<(i), (j)>::val

enum ET : unsigned long long {
    ET1 =     SAMENUM(1uLL<<2, 4),
    ET2fail = SAMENUM(1uLL<<3, 4), // compile time error
    ET4 =     SAMENUM(1uLL<<40, 1099511627776uLL),
};
Run Code Online (Sandbox Code Playgroud)

这一切看起来都不错,但我们并不是真的喜欢宏.

一个问题:我们可以对constexpr函数做同样的事情,但没有错误可读性回归吗?

我能想到的最接近的解决方案是:

constexpr unsigned long long SameNum(unsigned long long i, unsigned long long j)
{
    return (i == j) ? i : (throw "Numbers not same!");
}
Run Code Online (Sandbox Code Playgroud)

但它会产生编译时错误

error: expression '<throw-expression>' is not a constant-expression
Run Code Online (Sandbox Code Playgroud)

而不是我在static_assert中写的任何东西

编辑:

下面的答案几乎是完美的,除了一个小的回归:调用比使用宏没有那么漂亮.

还有一种方法(比使用static_assert更糟糕,但在使用中更"漂亮")

int NumbersNotSame() { return 0; }

constexpr unsigned long long SameNum(unsigned long long i, unsigned long long j)
{
    return (i == j) ? i : (NumbersNotSame());
}
Run Code Online (Sandbox Code Playgroud)

Ric*_*ges 6

constexpr函数中的static_assert:

template<unsigned long long I, unsigned long long J>
constexpr unsigned long long SameNum()
{
    static_assert(I == J, "numbers don't match");
    return I;
}

enum ET : unsigned long long {
    ET1 =     SameNum<1uLL<<2, 4>(),
    ET2fail = SameNum<1uLL<<3, 4>(), // compile time error
    ET4 =     SameNum<1uLL<<40, 1099511627776uLL>(),
};
Run Code Online (Sandbox Code Playgroud)