2017-10-16 60 views
4

在下面的示例中main可以static_assert如果字符串文字以'v'开头,但verify不能。如何静态断言constexpr函数内的字符串文字的条件?

为什么会发生?有没有一种方法允许verifystatic_assert条件字符串中的字符?

#include <cstddef> 

template <std::size_t N> 
constexpr char get_first(const char (&str)[N]) 
{ 
    static_assert(N>1, "must be > 1"); 
    return str[0]; 
} 

template <std::size_t N> 
constexpr void verify(const char (&str)[N]) 
{ 
    static_assert(str[0] == 'v', "must start from v"); 
} 

int main() 
{ 
    static_assert(get_first("value") == 'v', "first must be 'v'"); // succeeds 
    verify("value"); // fails to compile 
} 

编译错误:

main.cpp: In instantiation of 'constexpr void verify(const char (&)[N]) [with long unsigned int N = 6]': 
main.cpp:19:15: required from here 
main.cpp:13:9: error: non-constant condition for static assertion 
     static_assert(str[0] == 'v', "must start from v"); 
     ^~~~~~~~~~~~~ 
main.cpp:13:9: error: 'str' is not a constant expression 

Example

+0

如果你想有一个字符串参数,你可以编译时断言,我建议花。 – chris

回答

1

的问题是,verify()

template <std::size_t N> 
constexpr void verify(const char (&str)[N]) 
{ 
    static_assert(str[0] == 'v', "must start from v"); 
} 

可以称为编译时运行时间。

所以错误,因为可以执行static_assert(),在str,调用时编译时间,但不能叫时运行时(当str的第一个字符是不知道编译时)。

- 编辑 -

的OP要求在字符串文字编译时检查。

下面是一个愚蠢的例子,我想是不是真的有用,但我希望能有所启发

template <char const * const str> 
constexpr bool startWithUpperLetter() 
{ 
    static_assert(str[0] != 'v', "no start with \'v\', please"); 

    return (str[0] >= 'A') && (str[0] <= 'Z'); 
} 

constexpr char const str1[] { "ABC" }; 
constexpr char const str2[] { "abc" }; 
constexpr char const str3[] { "vwx" }; 

int main() 
{ 
    static_assert(startWithUpperLetter<str1>() == true, "!"); 
    static_assert(startWithUpperLetter<str2>() == false, "!"); 
    // static_assert(startWithUpperLetter<str3>() == false, "!"); // error 
} 
+0

是否有任何语言规则使得函数或函数调用的运行时间比我们想象的要少,或编译时间少于我们想象的? –

+0

@NickyC - 不确定要理解你的问题,但是......没有'constexpr',函数只是(理想的)运行时; 'constexpr'是运行时**和**编译时启用的,我不知道一种强制编译时启用的方法;如果你想要的东西只能在编译时工作,我想你必须使用模板元编程。 – max66

+0

@ max66有没有办法强制在编译时发生'verify'的评估,以便我可以'static_assert'在那里?有没有办法用模板元编程来分析字符串文字中的字符? –

2

我有另一种解决办法给你。这不会使用static_assert,但保证在编译时强制执行条件。

#include <type_traits> 
template<bool b> 
using enforce = std::bool_constant<b>; 

template <std::size_t N> 
constexpr int verify(const char (&str)[N]) 
{ 
    if(get_first(str) != 'v') { 
     throw "must start from v"; 
    } 
    return 0; 
} 

int main() 
{ 
    using assertion = enforce<verify("value")>; // compiles 
    using assertion = enforce<verify("fail")>; // fails to compile 
    // or use it like 
    constexpr auto assertion0 = verify("value"); // compiles 
} 

这使用throwing在constexpr上下文中无效。您会收到错误看起来somethign像这样:

26 : <source>:26:31: error: non-type template argument is not a constant expression 
    using assertion = enforce<verify("fail")>; // fails to compile 
           ^~~~~~~~~~~~~~ 
15 : <source>:15:9: note: subexpression not valid in a constant expression 
     throw "must start from v"; 
     ^
26 : <source>:26:31: note: in call to 'verify("fail")' 
    using assertion = enforce<verify("fail")>; // fails to compile 

我们可以使用它作为一个模板参数执行的verify constexpr评价。这也是声明一个非void返回类型的原因。

+2

另一种方法是将'verify()'的值存储在'constexpr'值中;例如:'constexpr int vr0 = verify(“value”); constexpr int vr1 = verify(“fail”);';在这种情况下,不需要“强制执行” – max66

3

在C++ 17中,可以将值包装在一个constexpr lambda(online demo)中。呼叫看起来像

verify([=] { return "value"; }); 

,并解开你可以

template <class StringWrapper> 
constexpr void verify(StringWrapper str_w) 
{ 
    constexpr auto str = str_w(); 
    static_assert(str[0] == 'v', "must start from v"); 
} 
相关问题