在以下示例中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
答案 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
}