2017-02-23 121 views
2

我想写一个函数,如果使用编译时常量参数调用它将触发编译时错误,如果参数的值doesn与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)语法,因为此代码旨在用于不熟悉模板语法的初学者程序员应该可以使用的库。

+2

值不能推断这样的线'模板空隙F(N){ '不可能是正确的 –

+1

编译时间或运行时间。你必须选择(或做两个功能)。 – xinaiz

+0

有没有办法用'constexpr'而不是模板来做? – AJMansfield

回答

5

我能想到的最好的方法是抛出异常的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 
} 

- 编辑 -

正如指出的,而不是抛出一个异常尤里kilocheck,你可以调用std::abort();通过示例

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

'std :: abort'也可以。但是这样的函数需要在constexpr上下文中进行调用,以便在编译时进行评估。 –

+0

@yurikilochek - 我习惯使用'throw'来解决这类问题,我没有考虑这个问题。你是对的;谢谢;根据它修改我的答案 – max66

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

传递给用作参数