这是我希望能够编写的代码:
int id1 = not_const_expr_1();
int id10 = not_const_expr_10();
constexpr Device& cD1 = get_device(1); // 1. ok
constexpr Device& cD10 = get_device(10); // 2. compile error
Device& cD1 = get_device(1); // 3. ok
Device& cD10 = get_device(10); // 4. compile error
Device& D1 = get_device(id1); // 5. ok
Device& D10 = get_device(id10); // 6. exception, log message, infinite loop, or something
这是我试过的:
template<typename T>
T failed(const char*) { while(1); } // could also throw exception
constexpr Device& dev1 = ...;
constexpr Device& dev42 = ...;
constexpr Device& get_device(uint8_t which) {
return which == 1 ? dev1 :
which == 42 ? dev42 :
// more here, but not important
failed<Device&>("Device does not exist");
// string argument just to aid with compiler error message
}
这传递了除了数字4之外的所有上述测试用例.不幸的是,错误没有在编译时被捕获,因为编译器发现对于给定的参数,get_device不是const_expr.
有没有什么方法可以在这里使用static_assert,而不会破坏非constexpr上下文中的内容?
最佳答案 这是一个接近的黑客:
#define _return_constexpr(x) static_assert(((void)x, true), ""); return x
template <uint8_t which>
constexpr Device& get_device() {
_return_constexpr(get_device(which));
}
通过测试为:
constexpr Device& cD1 = get_device(1); // 1a. ok
constexpr Device& cD1 = get_device<1>(); // 1b. ok
constexpr Device& cD10 = get_device(10); // 2a. compile error
constexpr Device& cD10 = get_device<10>(); // 2b. compile error
Device& cD1 = get_device(1); // 3a. ok
Device& cD1 = get_device<1>(); // 3b. ok
Device& cD10 = get_device(10); // 4a. runtime error (FAIL)
Device& cD10 = get_device<10>(); // 4b. compile error (PASS!)
Device& D1 = get_device(id1); // 5. ok
Device& D10 = get_device(id10); // 6. ok
似乎static_assert是强制constexpr评估的唯一上下文:
>适用于任何类型(模板参数不接受Device&)
>在constexpr上下文中工作(数组大小需要声明)
有没有更简洁的方法来编写这个宏?
如果没有要求结果本身在constexpr上下文中工作,我们可以放弃宏:
template <uint8_t which>
Device& get_device() {
constexpr auto& ret = get_device(which);
return ret;
}