【问题标题】:Generate compile-time error if compile-time-constant parameter is wrong如果 compile-time-constant 参数错误,则生成编译时错误
【发布时间】:2017-02-23 19:37:41
【问题描述】:

我正在尝试编写一个函数,如果使用编译时常量参数调用,如果参数的值与static_assert 不匹配,它将触发编译时错误,但仍可以在具有计算值的运行时。

有点像这样:

template<int N> void f(N){
  static_assert(N == 5, "N can only be 5.");
  do_something_with(N);
}

void f(int N){
  if(N == 5){
    do_something_with(N);
  }
}

volatile int five = 5;
volatile int six = 6;

int main() {  
  f(5); //ok
  f(6); //compile-time error
  f(five); //ok
  f(six); //run-time abort

  return 0;
}

我该怎么做?

另外,如果可能的话,我希望能够保留简单的f(something) 语法,因为此代码适用于不熟悉模板语法的初学者程序员应该可以使用的库。

【问题讨论】:

  • 无法推导出作为参数传递给函数的值,因此template&lt;int N&gt; void f(N){ 行不正确
  • 编译时或运行时。你必须选择(或做两个功能)。
  • 有没有办法使用constexpr 而不是模板的东西?
  • @BlackMoses 函数能够执行运行时错误/异常并不是绝对必要的,但它需要能够使用编译时不可用的值来调用它。

标签: c++ c++11 templates overloading static-assert


【解决方案1】:

我能想象到的最好的方法是抛出异常的 constexpr 函数。

如果在编译时执行,throw 会导致编译错误;如果在运行时执行,则抛出异常

有点像

#include <stdexcept>

constexpr int checkGreaterThanZero (int val)
 { return val > 0 ? val : throw std::domain_error("!"); }

int main()
 {
   // constexpr int ic { checkGreaterThanZero(-1) }; // compile error

   int ir { checkGreaterThanZero(-1) }; // runtime error
 }

-- 编辑--

正如 yurikilocheck 所指出的,您可以调用std::abort(),而不是抛出异常;举例

constexpr int checkGreaterThanZero (int val)
 { return val > 0 ? val : (std::abort(), 0); }

【讨论】:

  • std::abort 也可以。但是这样的函数需要在 constexpr 上下文中调用才能在编译时进行评估。
  • @yurikilochek - 我习惯用throw来解决这类问题,没想到;你说得对;谢谢;根据它修改了我的答案
【解决方案2】:

使用不同的语法,你可以这样做:

template <int N>
using int_c = std::integral_constant<int, N>;

namespace detail {
    template <std::size_t N>
    constexpr int to_number(const int (&a)[N])
    {
        int res = 0;
        for (auto e : a) {
            res *= 10;
            res += e;
        }
        return res;
    }
}

template <char ... Ns>
constexpr int_c<detail::to_number({(Ns - '0')...})> operator ""_c ()
{
    return {};
}

#if 1 // Write this way
// Compile time
template <int N> void f(int_c<N>) = delete;
void f(int_c<5>) { do_something_with(5); }

#else // Or like this
// Compile time
template <int N>
void f(int_c<N>)
{
    static_assert(N == 5, "!");
    do_something_with(N);
}

#endif

// Runtime
void f(int N){
    if (N == 5) {
        std::abort(); // Or any other error handling
    }
    f(5_c);
}

int main(){
    f(5_c); // ok
    // f(6_c); // Won't compile
    f(5); // ok
    f(6); // abort at runtime
}

Demo

【讨论】:

    猜你喜欢
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多