如何静态断言constexpr函数内的字符串文字?

时间:2017-10-16 01:49:43

标签: c++ c++14 constexpr static-assert

在以下示例中main static_assert如果字符串文字以'v'开头,verify则不能。{/ p>

为什么会这样?有没有办法在字符串文字中对字符允许verify static_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

3 个答案:

答案 0 :(得分: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");   
}

答案 1 :(得分: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
}

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

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 :(得分: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
 }