在下面的示例中,main
可以static_assert
字符串文本是否以 'v'
开头,但verify
不能。
为什么会这样?有没有办法允许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
例。
我有另一种解决方法。这不会使用 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
}
这使用抛出在 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 返回类型的原因。
在 C++17 中,您可以将值包装在 constexpr lambda 中(在线演示)。呼叫看起来像
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");
}
问题是verify()
template <std::size_t N>
constexpr void verify(const char (&str)[N])
{
static_assert(str[0] == 'v', "must start from v");
}
可以称为编译时和运行时。
所以错误,因为可以在str
上执行static_assert()
,当调用编译时,但不能在调用运行时(当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
}