我有一个constexpr函数,看起来像这样:
constexpr int foo(int bar)
{
static_assert(bar>arbitrary_number, "Use a lower number please");
return something_const;
}
Run Code Online (Sandbox Code Playgroud)
但是,使用GCC 4.6.3进行编译时不断告诉我
错误:'bar'不能出现在常量表达式中
我试过类似的东西
constexpr int foo(constexpr const int bar)
{
static_assert(bar>arbitrary_number, "Use a lower number please");
return something_const;
}
Run Code Online (Sandbox Code Playgroud)
但constexpr不能用于函数参数.
是否有一些简单的方法告诉编译器bar始终是编译时常量?
template<typename T> constexpr inline
T getClamped(const T& mValue, const T& mMin, const T& mMax)
{
assert(mMin < mMax); // remove this line to successfully compile
return mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue);
}
Run Code Online (Sandbox Code Playgroud)
错误:constexpr函数的主体 'constexpr T getClamped(const T&,const T&,const T&)[with T = long unsigned int]' not return-statement
用g++ 4.8.1.clang++ 3.4不抱怨
谁在这?我可以g++在不使用宏的情况下编译代码吗?
如果声明了一个对象const,则保证其值仅在运行时可用,但如果声明constexpr了该值,则保证该值在编译期间和运行时都可用.因此,如果我有一个在编译期间值可用的对象,是否有任何我不应该声明它的情况constexpr?
const int magicValue = 42; // Does this ever make sense
// (using const instead of constexpr)?
Run Code Online (Sandbox Code Playgroud)
对于函数,如果函数可以返回编译期间计算的值,当在编译期间传递带有值的参数时,是否有意义不声明函数constexpr?
struct Point { int x; int y; };
Point midPoint(Point p1, Point p2) // Does this ever make
{ // sense (not declaring
return { (p1.x + p2.x) / 2 , (p1.y + p2.y) / 2 }; // the function
} // constexpr)?
Run Code Online (Sandbox Code Playgroud)
我能想到的唯一情况是当你不想提交能够在使用known-at-compile-time参数调用时计算编译时常量的函数,例如,如果你想保持灵活性改变midPoint实现而不改变其界面(从而可能破坏调用者).例如,您可能希望保留将非constexpr副作用添加到midPoint例如IO 的灵活性.
我有一个带有constexpr值构造函数的类,但没有复制或移动ctor
class C {
public:
constexpr C(int) { }
C(const C&) = delete;
C& operator=(const C&) = delete;
};
int main() {
constexpr C arr[] = {1, 2};
}
Run Code Online (Sandbox Code Playgroud)
我发现这段代码不起作用,因为它实际上是试图使用移动构造函数C而不是值构造函数来构造.一个问题是我希望这个对象不可移动(出于测试目的),但我认为"好吧,好吧,我会添加一个移动构造函数."
class C {
public:
constexpr C(int) { }
C(const C&) = delete;
C& operator=(const C&) = delete;
C& operator=(C&&) = delete;
C(C&&) { /*something*/ } // added, assume this must be non trivial
};
Run Code Online (Sandbox Code Playgroud)
好的,现在它使用移动构造函数,一切都在gcc下运行但是当我使用clang时,它会抱怨因为移动构造函数没有标记constexpr
error: constexpr variable 'arr' must be initialized by …Run Code Online (Sandbox Code Playgroud) 应该不是的std ::调用是constexpr特别是在C++中17 constexpr lambda表达式?
是否有任何阻碍这种情况的障碍?
这个问题似乎与现有问题有关,但我不理解答案中提供的"便携式解决方法" (涉及const auto this_ = this;),而且我认为以下示例更容易理解.
我正在使用以下C++ 17代码片段(现场演示):
#include <iostream>
struct Test {
const char* name_{nullptr};
const Test* src_{nullptr};
constexpr Test(const char* name) noexcept
: name_{name}
{}
constexpr Test(const Test& src) noexcept
: src_{&src}
{
name_ = src_->name_;
src_ = nullptr;
}
};
template<char c>
void print_constexpr_char() {
std::cout << c << std::endl;
}
int main() {
constexpr const char* in = "x";
constexpr auto foo = Test{in};
constexpr auto bar = …Run Code Online (Sandbox Code Playgroud) 以下是未定义行为的两个测试用例,表示为 IIFE(立即称为 Lambda-Axpression):
constexpr auto test3 = []{
int* p{};
{
int x{};
p = &x;
}
return *p; // Undefined Behaviour
}(); // IIFE
constexpr auto test4 = []{
int x = std::numeric_limits<int>::min();
int y = -x; // Undefined Behaviour
return y;
}();
int main() {}
Run Code Online (Sandbox Code Playgroud)
当使用 GCC 主干编译时,test4被正确拒绝,因为它在constexpr. 另一方面test3是接受。
GCC 是否有权接受test3?
在 C++11 constexpr 函数中,assert()不可能使用第二个语句,例如 an 。Astatic_assert()很好,但如果该函数被称为“正常”函数,则它不起作用。逗号运算符可以来帮助wrto。的assert(),而是丑陋和一些工具吐出它的警告。
考虑这样的“getter”,它在断言旁边是完全可构造的。但是我想为运行时和编译时保留某种断言,但不能仅根据“constexpr”上下文进行重载。
template<int Size>
struct Array {
int m_vals[Size];
constexpr const int& getElement( int idx ) const
{
ASSERT( idx < Size ); // a no-go for constexpr funcs in c++11
// not possible, even in constexpr calls as being pointed out, but what I would like:
static_assert( idx < Size, "out-of-bounds" );
return m_vals[idx];
}
};
Run Code Online (Sandbox Code Playgroud)
附带条件:C++11,无堆,无异常,无编译器细节。
注意正如评论者指出的那样(谢谢!),static_assert论点是不可能的(但会很好)。在这种情况下,编译器在越界访问时给了我一个不同的错误。
考虑以下片段:
static constexpr uint8_t a = 0;
static constexpr const int8_t *b = reinterpret_cast<const int8_t *>(&a);
Run Code Online (Sandbox Code Playgroud)
这无法通过 编译error: a reinterpret_cast is not a constant expression,因为C++ 标准禁止使用reinterpret_castin constexpr。
但是,如果我想将值 b 存储在PROGMEM(对于 AVR 微控制器)中,编译会成功:
static constexpr uint8_t a = 0;
static const int8_t PROGMEM *const b = reinterpret_cast<const int8_t *>(&a);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,编译器能够证明该表达式reinterpret_cast<const int8_t *>(&a)是编译时常量,因为它将其结果(指向某个包含零的字节的地址)插入到二进制程序空间中:
_ZL1g:
.zero 1
.section .progmem.data,"a",@progbits
.type _ZL1b, @object
.size _ZL1b, 2
_ZL1b:
.word _ZL1g
Run Code Online (Sandbox Code Playgroud)
另外,我的理解是这reinterpret_cast是一个编译时指令。那么为什么它不能在 a …
我有什么保证可能包含 constexpr 函数调用的核心常量表达式(如在 [expr.const].2 中)将在编译时实际评估,这取决于哪些条件?
constexpr通过将计算移至翻译阶段(编译时),引入隐式承诺提高运行时性能。这两点似乎相互矛盾。
在什么情况下可以依靠编译器在编译时解析核心常量表达式(可能包含任意复杂的计算)而不是将其推迟到运行时?
至少在-O0gcc下似乎实际上发出代码并调用 constexpr 函数。在-O1最多不。
难道我们不得不求助于挂羊头卖狗肉,如这个,那个力量通过模板系统constexpr:
template <auto V>
struct compile_time_h { static constexpr auto value = V; };
template <auto V>
inline constexpr auto compile_time = compile_time_h<V>::value;
constexpr int f(int x) { return x; }
int main() {
for (int x = 0; x < compile_time<f(42)>; ++x) {}
}
Run Code Online (Sandbox Code Playgroud)