是否可以使用constexpr?连接两个字符串文字?或者换句话说,可以在代码中消除宏,如:
#define nl(str) str "\n"
int main()
{
std::cout <<
nl("usage: foo")
nl("print a message")
;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
更新:使用没有任何问题"\n",但我想知道是否可以constexpr用来替换这些类型的宏.
这些可能应该是在不同的问题,但它们是相关的......
为什么我们需要写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索引)
我是编程新手,我开始使用C++编程原理和实践来学习它.今天我在这里是因为我在理解constexpr功能方面遇到了一些问题.在第8章中,作者在某些方面介绍了它们,并使用这些词语作了简短的例子:
函数表示计算,有时我们想在编译时进行计算.希望编译器评估计算的原因通常是避免在运行时进行数百万次相同的计算.
我们通过将函数声明为函数来传达我们打算在编译时评估
constexpr函数.一个constepxr函数可以在仅仅如果它被赋予常量表达式作为参数编译时进行评估.Run Code Online (Sandbox Code Playgroud)constexpr double xscale = 10; // scaling factors constexpr double yscale = 0.8; constexpr Point scale(Point p) { return { xscale*p.x, yscale*p.y }; };假设该点是一个简单的结构,其中成员x和y代表2D坐标.现在,当我们给出
scale()一个Point参数时,它会返回一个坐标根据因子xscale而缩放的点yscale.例如:Run Code Online (Sandbox Code Playgroud)void user(Point p1) { Point p2{10,10}; Point p3 = scale(p1); Point p4 = scale(p2) // p4 == {100,8} constexpr Point p5 = scale(p1); // error : scale(p1) is not a constant expression constexpr Point p6 = …
以下代码无法在Ideone上实时编译:
#include <iostream>
using namespace std;
int main() {
const double kPi = 3.14;
constexpr double kPi2 = 2.0*kPi;
cout << kPi2;
}
Run Code Online (Sandbox Code Playgroud)
错误消息是:
Run Code Online (Sandbox Code Playgroud)prog.cpp: In function 'int main()': prog.cpp:6:30: error: the value of 'kPi' is not usable in a constant expression constexpr double kPi2 = 2.0*kPi; ^ prog.cpp:5:15: note: 'kPi' was not declared 'constexpr' const double kPi = 3.14;
将const声明替换为kPiwith constexpr,它会成功编译.
在另一方面,如果int是用来代替double,好像const 还有戏剧与constexpr …
我已经实现了constexpr这样的数组:
template <typename T>
class const_array {
const T* p;
unsigned n;
public:
template <unsigned N>
constexpr const_array(const T(&a)[N]): p(a), n(N) { }
constexpr unsigned size() const { return n; }
};
int main(int argc, char* argv[]) {
// works
static_assert(const_array<double>{{1.,2.,3.}}.size() == 3);
// doesn't compile
constexpr const_array<double> a{{1.,2.,3.}};
static_assert(a.size() == 3);
}
Run Code Online (Sandbox Code Playgroud)
为什么第一次static_assert编译,但初始化a失败?我正在使用gcc 6.2.0.我越来越
: In function 'int main(int, char**)':
: error: 'const_array<double>{((const double*)(&<anonymous>)), 3u}' is not a constant expression
constexpr const_array<double> a{{1.,2.,3.}}; …Run Code Online (Sandbox Code Playgroud) 我有自己的固定大小数组类型我希望可以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++ 吗?
int main() {
constexpr auto sz = __func__ - __func__;
return sz;
}
Run Code Online (Sandbox Code Playgroud)
GCC 和 MSVC 认为可以,Clang 认为不是:Compiler Explorer。
所有编译器都同意这个是可以的:Compiler Explorer。
int main() {
constexpr auto p = __func__;
constexpr auto p2 = p;
constexpr auto sz = p2 - p;
return sz;
}
Run Code Online (Sandbox Code Playgroud)
Clang 再次不喜欢这个,但其他人都可以:编译器资源管理器
int main() {
constexpr auto p = __func__;
constexpr auto p2 = __func__;
constexpr auto sz = p2 - p;
return sz;
}
Run Code Online (Sandbox Code Playgroud)
这里有什么?我认为对无关指针的算术是未定义的行为,但__func__返回相同的指针,不是吗?我不确定,所以我想我可以测试一下。如果我没记错的话, …
在 C++20 中,std::swap变成constexpr函数。
我知道标准库在标记事物方面确实落后于语言constexpr,但到 2017 年,<algorithm>它和其他一些东西几乎都是 constexpr。然而 -std::swap不是。我依稀记得有一些奇怪的语言缺陷阻止了那个标记,但我忘记了细节。
有人可以简洁明了地解释这一点吗?
动机:需要理解为什么在 C++11/C++14 代码中标记一个std::swap()-like 函数可能是个坏主意constexpr。
c++ ×10
constexpr ×10
c++11 ×5
c++17 ×2
arrays ×1
c++14 ×1
c++20 ×1
compile-time ×1
const ×1
constructor ×1
oop ×1
pointers ×1