如何静态断言constexpr函数内的字符串文字的条件?
在下面的示例中main
可以static_assert
如果字符串文字以'v'
开头,但verify
不能。如何静态断言constexpr函数内的字符串文字的条件?
为什么会发生?有没有一种方法允许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
的问题是,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
}
是否有任何语言规则使得函数或函数调用的运行时间比我们想象的要少,或编译时间少于我们想象的? –
@NickyC - 不确定要理解你的问题,但是......没有'constexpr',函数只是(理想的)运行时; 'constexpr'是运行时**和**编译时启用的,我不知道一种强制编译时启用的方法;如果你想要的东西只能在编译时工作,我想你必须使用模板元编程。 – max66
@ max66有没有办法强制在编译时发生'verify'的评估,以便我可以'static_assert'在那里?有没有办法用模板元编程来分析字符串文字中的字符? –
我有另一种解决办法给你。这不会使用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返回类型的原因。
另一种方法是将'verify()'的值存储在'constexpr'值中;例如:'constexpr int vr0 = verify(“value”); constexpr int vr1 = verify(“fail”);';在这种情况下,不需要“强制执行” – max66
在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");
}
如果你想有一个字符串参数,你可以编译时断言,我建议花。 – chris