我正在玩一些使用c ++ 11的玩具代码来弄清楚事情是如何运作的.在此期间,我遇到了以下问题,简化为:
template <int x, int y>
class add {
public:
static constexpr int ret = x + y;
};
constexpr int addFunc(const int x, const int y) {
return add<x,y>::ret;
}
int main() {
const int x = 1;
const int y = 2;
cout << add<x,y>::ret << endl; // Works
cout << addFunc(1,2) << endl; // Compiler error
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用GCC 4.8.1并且输出为:
'x'不是模板参数中的常量表达式,用于'int'类型
'y'不是类型'int'的模板参数中的常量表达式
我试图计算的两种方式之间究竟有什么区别add::ret?这两个值都应该在编译时可用.
我是编程新手,我开始使用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 = …
我之前根据参数是否constexpr询问函数重载.我正试图解决这个问题的令人失望的答案,以建立一个更聪明的断言功能.这大致是我想做的事情:
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
Run Code Online (Sandbox Code Playgroud)
基本上,我们的想法是编译时检查总是比运行时检查更好,如果可以在编译时检查.但是,由于内联和常量折叠之类的东西,我不能总是知道是否可以进行编译时间检查.这意味着可能存在assert (condition)编译的情况,assert(false)代码只是等待我运行它并在我发现错误之前执行该路径.
因此,如果有某种方法来检查条件是否是constexpr(由于内联或其他优化),我可以static_assert在可能的情况下调用,否则返回运行时断言.幸运的是,gcc具有内在函数__builtin_constant_p (exp),如果exp是constexpr 则返回true .我不知道其他编译器是否有这种内在的,但我希望这可以解决我的问题.这是我提出的代码:
#include <cassert>
#undef IS_CONSTEXPR
#if defined __GNUC__
#define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
#define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers
inline void smart_assert (bool const condition) {
static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
if (!IS_CONSTEXPR(condition))
assert (condition);
}
#undef IS_CONSTEXPR
Run Code Online (Sandbox Code Playgroud)
该static_assert …
constexpr uint32_t BitPositionToMask(int i,int Size){
static_assert(i < Size,"bit position out of range");
return 1 << i;
}
Run Code Online (Sandbox Code Playgroud)
这会产生:
error: non-constant condition for static assertion
Run Code Online (Sandbox Code Playgroud)
在GCC 4.6.2我没有得到什么或这是一个GCC错误?
更新: 谢谢Andy再次成为我的书呆子守护天使.因为我在编译时有值,所以我只是把它作为模板,它按预期工作.
template<int i,int Size>
constexpr uint32_t BitPositionToMask(){
static_assert(i < Size,"bit position out of range");
return 1 << i;
}
Run Code Online (Sandbox Code Playgroud) 以下代码不能用g ++/clang ++编译.
constexpr int bar(int v) {
if (v > 0){
return v * 2;
}
return 2;
}
constexpr int foo(const int v) {
constexpr auto x = bar(v); // error
return v;
}
int main() {
constexpr auto a = foo(1);
constexpr auto b = bar(1); // ok
}
Run Code Online (Sandbox Code Playgroud)
错误消息是:x必须由常量表达式初始化
但是从行(ok)你看到bar()是constexpr.
如果我将foo()的主体改为
constexpr int foo(const int v) {
return bar(v);
}
Run Code Online (Sandbox Code Playgroud)
没关系!
我不清楚,为什么第一种形式不可能.我使用g ++ - 6.2.1,g ++ - 7.0.0和clang ++ - 3.9.0
我有这段代码:
template <int V>
struct Constant {
constexpr operator int() const noexcept { return V; }
};
template <class T, int N>
struct Array { };
auto function(auto s) -> Array<int, s + s> {
return {};
}
auto const a = function(Constant<3>{});
Run Code Online (Sandbox Code Playgroud)
让我最悲伤的是,似乎只有 Clang 接受这个代码。
哪个编译器是正确的,为什么?
为什么非编译时计算函数“产品”可以是constexpr?
#include <iostream>
constexpr int product(int x, int y) {
return x * y;
}
int main(int argc, char* argv[]) {
using namespace std;
int x1, y1 = 0;
cout << "input x1:\n";
cin >> x1;
cout << "input y1:\n";
cin >> y1;
const int a = product(x1, y1);
cout << a << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)