这些可能应该是在不同的问题,但它们是相关的......
为什么我们需要写constexpr?鉴于一组限制,编译器无法评估代码以确定它是否满足constexpr要求,并将其视为constexpr是否满足要求?作为一个纯粹的文档关键字,我不确定它是否成立,因为我无法想到我(其他人的constexpr功能的用户)应该真正关心它是否运行时的情况.
这是我的逻辑:如果它是一个昂贵的函数,我认为作为一个良好的实践,我应该这样对待它,无论我是否给它编译时常量输入.这可能意味着在加载时调用它并保存结果,而不是在执行的关键点调用它.原因是因为constexpr实际上并没有向我保证它不会在运行时首先执行 - 所以也许一个新的/不同的机制应该这样做.
这些constexpr限制似乎排除了许多(如果不是大多数)函数的编译时评估,逻辑上可能是这样.我已经读过这至少部分(或者可能完全是?)来防止无限循环并挂起编译器.但是,如果这是该原因,是合法的?
对于constexpr使用给定输入的任何给定函数,编译器是否应该能够计算它是否无限循环?这不是解决停机问题的任何输入.constexpr函数的输入是编译时常量和有限,因此编译器只需检查有限输入的无限循环:实际使用的输入.如果编写编译时无限循环,则应该是常规编译错误.
基本上我想在我的代码中能够做到这一点:
Engine.getById(WSID('some-id'));
Run Code Online (Sandbox Code Playgroud)
哪个应该改变
Engine.getById('1a61bc96');
Run Code Online (Sandbox Code Playgroud)
就在编译成asm之前.所以在编译时.
这是我的尝试
constexpr int WSID(const char* str) {
boost::crc_32_type result;
result.process_bytes(str,sizeof(str));
return result.checksum();
}
Run Code Online (Sandbox Code Playgroud)
但是在尝试使用MSVC 18(CTP 2013年11月)编译时我得到了这个
error C3249: illegal statement or sub-expression for 'constexpr' function
Run Code Online (Sandbox Code Playgroud)
WSID只要在编译期间完成,我怎样才能以这种方式或任何方式获得该函数?
试过这个:编译时间字符串哈希
warning C4592: 'crc32': 'constexpr' call evaluation failed; function will be called at run-time
Run Code Online (Sandbox Code Playgroud)
编辑:
我第一次在Jason Gregory的游戏引擎架构中听说过这种技术.我联系了那位有意回答我的作者:
我们所做的是通过一个自定义的小预处理器传递我们的源代码,该预处理器搜索表单的文本
SID('xxxxxx')并将单引号之间的任何内容转换为其哈希等效项作为十六进制文字(0xNNNNNNNN).[...]你可以想象通过宏和/或一些模板元编程也可以做到这一点,尽管如你所说让编译器为你做这种工作是很棘手的.这并非不可能,但编写自定义工具更容易,也更灵活.[...]
另请注意,我们为
SID('xxxx')文字选择单引号.这样做是为了让我们在代码编辑器中得到一些合理的语法突出显示,但是如果出现问题并且一些未预处理的代码通过编译器,它会引发语法错误,因为单引号通常是保留的单字符文字.另请注意,让您的小预处理工具将字符串缓存到某种类型的数据库中是至关重要的,这样可以在给定哈希码的情况下查找原始字符串.当您调试代码并检查
StringId变量时,调试器通常会向您显示相当难以理解的哈希代码.但是使用SID数据库,您可以编写一个插件,将这些哈希代码转换回其字符串等效项.这样,你会在你的观察窗口看到SID('foo'),而不是0x75AE3080[...].此外,游戏应该能够加载这个相同的数据库,以便它可以在屏幕上打印字符串而不是十六进制哈希码用于调试目的[...].
但是虽然预处理有一些主要优点,但这意味着我必须准备一些修改文件的输出系统(那些将存储在别处,然后我们需要告诉MSVC).因此,它可能会使编译任务复杂化.有没有办法用python预处理文件,例如没有头痛?但这不是问题,我仍然对使用编译时功能感兴趣(关于缓存我可以使用ID索引)
我有自己的固定大小数组类型我希望可以constexpr从一个可构造的,std::initializer_list而无需显式定义大小模板参数.
我以为我可以使用模板演绎指南,但看起来它并没有被std::initializer_list::size()视为constexpr函数.
这是一个尝试制作演绎指南的例子std::array(类似于我的类型并且有相同的问题):
namespace std
{
template<typename T> array(initializer_list<T> initialiserList) -> array<T, initialiserList.size()>;
}
static constexpr std::array myArray = {1,2,3};
static constexpr std::array myArray2 = {{1,2,3}};
Run Code Online (Sandbox Code Playgroud)
我已经尝试了MSVC和Clang,两者都给出了大致相同的错误:
myArray有一个错误抱怨该函数的参数太多.
myArray2说"替换失败[使用T = int]:非类型模板参数不是常量表达式"
我试图把constexpr在扣除指南或函数参数的前面,但它们似乎也没有被允许,所以看来扣除指南是无效的,即使它应该在正常工作constexpr范围内.
有没有办法让这项工作不走这make_array()条路?
我有一个constexpr类Debug:
struct Debug {
constexpr Debug(bool a, bool b, bool c) : a(a), b(b), c(c) {}
bool a, b, c;
constexpr bool get() const { return a; }
};
int main() {
Debug dbg(true, false, false); // is dbg constexpr object?
constexpr Debug dbg2(0, 0, 0); // is constexpr redundant here?
}
Run Code Online (Sandbox Code Playgroud)
如您所见,这dbg是一个constexpr对象,因为它是用constexpr构造函数初始化的,所以如果我用constexpr对其进行限定,那有什么意义呢?
dbg和dbg2。谢谢。我正在使用C++ 14中的constexpr函数进行实验.以下代码计算析因是按预期工作的:
template <typename T>
constexpr auto fact(T a) {
if(a==1)
return 1;
return a*fact(a-1);
}
int main(void) {
static_assert(fact(3)==6, "fact doesn't work");
}
Run Code Online (Sandbox Code Playgroud)
用clang编译如下:
> clang++ --version
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
> clang++ -std=c++14 constexpr.cpp
Run Code Online (Sandbox Code Playgroud)
但是,当我更改fact定义以使用三元?运算符时:
template <typename T>
constexpr auto fact(T a) {
return a==1 ? 1 : a*fact(a-1);
}
Run Code Online (Sandbox Code Playgroud)
我得到以下编译器错误:
> clang++ -std=c++14 constexpr.cpp
constexpr.cpp:12:31: fatal error: recursive template instantiation exceeded maximum depth of
256
return a==T(1) ? …Run Code Online (Sandbox Code Playgroud) 我一直在尝试在编译时计算的 const 表达式。但是我玩了一个在编译时执行时看起来非常快的示例。
#include<iostream>
constexpr long int fib(int n) {
return (n <= 1)? n : fib(n-1) + fib(n-2);
}
int main () {
long int res = fib(45);
std::cout << res;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行此代码时,大约需要 7 秒才能运行。到现在为止还挺好。但是,当我更改long int res = fib(45)到const long int res = fib(45)它需要没有哪怕一秒钟。据我了解,它是在编译时评估的。
但是编译大约需要0.3秒
编译器怎么能这么快地评估它,但在运行时却需要更多的时间?我正在使用 gcc 5.4.0。
我知道在编译时复制任意内存块并不总是可能的,但既然我们得到了 constexpr 容器、虚拟方法和算法,为什么不也复制 memcpy 呢?这也是一种算法。
\n此外,
\nstd::bit_cast看起来很像std::memcpy解决方法reinterpret_cast,但它确实是constexpr。std::copy使用迭代器被标记为constexprC++20,因此对于类型来说复制是可能的。用法是复制或只是“重新解释”constexpr函数中的变量/数组,据我所知,前者没有解决std::bit_cast。特别是这个问题和我的答案想用它。
std::bit_cast可以是 constexpr 而std::memcpy不能是有什么特殊原因吗?std::bit_cast和 中的迭代器std::copy。C++20 bit_cast vs reinterpret_cast的相关答案简要引用于某处:
\n\n此外,目前不可能实现 constexpr\n位转换函数,因为 memcpy 本身不是 \xe2\x80\x99t constexpr。将提议的函数标记为 constexpr 不需要或阻止 memcpy 变成 …
从 C++20 开始,我们可以在编译时分配内存,我们必须在编译时释放它。因此,这给我提出了一些问题:首先,为什么这行得通?
constexpr int* return_ptr() {
return new int{ 1 };
}
void call_return_ptr(){
int* int_ptr = return_ptr();
}
int main() {
call_return_ptr();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用从编译时返回的 ptrconstexpr并且没有释放它。根据我的理解,这应该是一个错误。其次,如果第一个示例有效,那么为什么这不起作用:
constexpr int* return_ptr() {
return new int{ 1 };
}
void call_return_ptr(){
constexpr int* int_ptr = return_ptr();
}
int main() {
call_return_ptr();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
即使我们在编译时尝试删除指针,如下所示:
constexpr int* return_ptr() {
return new int{ 1 };
}
constexpr void call_return_ptr(){
constexpr int* int_ptr = return_ptr();
delete int_ptr;
} …Run Code Online (Sandbox Code Playgroud) 对于可选的内部内容,可选是否需要放置新的内容才能重建内部就地存储或联合?是否有一些新功能(例如 C++ 20 中的placement new)允许 std::Optional 的 constexpr 赋值?
template< class U = T >
optional& operator=( U&& value );
(since C++17)
(until C++20)
template< class U = T >
constexpr optional& operator=( U&& value );
(since C++20)
Run Code Online (Sandbox Code Playgroud) 我不确定我是否太na\xc3\xafve 或者只是太无知。
\n但为什么下面的内容有所不同呢?
\nconstexpr auto nInitialCapacity1 = std::wstring().capacity();\nconst auto nInitialCapacity2 = std::wstring().capacity();\nRun Code Online (Sandbox Code Playgroud)\n在 Visual Studio 2022/17.0.5 中,上述代码导致:
\nnInitialCapacity1 = 8\nnInitialCapacity2 = 7\nRun Code Online (Sandbox Code Playgroud)\n为什么(编译时)版本的结果constexpr不等于const调用的版本?
感谢您的任何解释!
\nc++ ×10
constexpr ×10
c++20 ×3
c++11 ×2
c++14 ×1
c++17 ×1
compile-time ×1
constants ×1
oop ×1
option-type ×1
stl ×1
template-argument-deduction ×1
visual-c++ ×1