c – 如何在constexpr函数中强制编译错误,而不是让它衰变到非constexpr上下文?

这是我希望能够编写的代码:

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