Fra*_*eux 3 c++ visual-c++ constexpr c++11 visual-studio-2015
在以下示例中,我用于static_assert
验证是否foo
在编译时确定.该static_assert
通行证和我有一个不正确的条件下,它实际上是积极的检查.这意味着foo
在编译时已知.但是,如果我使用调试器逐步执行代码,我会看到它skip_first_word
也在运行时执行.
// Skip the first word in p_str
constexpr const char * skip_first_word(const char * p_str) {
return (*p_str == '\0') ? p_str :
(*p_str == ' ') ? p_str + 1 :
skip_first_word(p_str + 1);
}
// constexpr to calculate the length of a string
constexpr size_t str_len(const char * p_str) {
return (*p_str == '\0') ? 0 : str_len(p_str + 1) + 1;
}
int main()
{
constexpr auto foo = skip_first_word("Hello, World!");
constexpr auto foo_size = str_len(foo);
static_assert(foo_size == 6, "Wrong size");
// This assert successfully fails
// static_assert(foo_size == 7, "Wrong size");
// Prevent optimizations
for(auto ptr = foo; *ptr != '\0'; ++ptr) {
volatile auto sink = ptr;
}
volatile auto sink = &foo_size;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?为什么不能foo
在运行时使用在编译时计算的那个?
编辑:使用Visual Studio 2015观察到此行为
gcc.godbolt.org显示您的代码使用标志完全使用gcc 7和clang 3.9进行了优化-std=c++11 -O1
.
取消注释volatile
操作显然会生成汇编指令,但不会为skip_first_word
或生成指令str_len
.
关于Visual Studio你是正确的:在gcc.beta.godbolt.org上使用CL 19表明正在为以下内容生成程序集:
constexpr auto foo = skip_first_word("Hello, World!");
constexpr auto foo_size = str_len(foo);
Run Code Online (Sandbox Code Playgroud)
这看起来像编译器实现缺陷,因为constexpr
变量应该并且可以在编译时完全计算.另外,变量在a中使用static_assert
,保证在编译时进行评估.这似乎表明,编译器产生不必要的装配skip_first_word
和str_len
,即使他们从来没有在运行时环境中使用.
手动内联代码如下...
static_assert(str_len(skip_first_word("Hello, World!")) == 6, "Wrong size");
static_assert(str_len(skip_first_word("Hello, World!")) != 7, "Wrong size");
Run Code Online (Sandbox Code Playgroud)