@cyberpunk_试图实现一些目标,并提出了一些问题,但所有的追逐都归结为:
是否可以构建一个工具来强制执行constexpr函数的编译时评估?
int f(int i) {return i;}
constexpr int g(int i) {return i;}
int main()
{
f(at_compilation(g, 0));
int x = at_compilation(g, 1);
constexpr int y = at_compilation(g, 2);
}
Run Code Online (Sandbox Code Playgroud)
在所有情况下,at_compilation强制执行g.
at_compilation不需要采用这种形式。
所有代码示例都有关于要求的限制。
清楚地解释这在 C++ 中如何不可行也是一个很好的答案。
我怀疑这是不可能的,基于@K-ballo / @Herb Sutter 的 回答 …
我有一个非常简单的项目,它在 VS2015 中产生奇怪的行为:
#include "Vec2f.h"
#include "StaticRendercomponent.h"
int main(int argc, char** argv)
{
constexpr Vec2f position(0.0f, 0.0f);
constexpr PhysicsComponent component(position, 15.0f);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
positionVS2015 以红色突出显示构造函数中的参数。将鼠标悬停在突出显示的内容上时,会出现以下消息:
constexpr Vec2f position = {(0.0f), (0.0f)}
expression must have constant value
Run Code Online (Sandbox Code Playgroud)
与错误突出显示和消息相反,程序编译和运行顺利,构建日志中没有任何消息,警告级别为 4 且“将警告视为错误”处于活动状态。
让 VS 显示这样的错误并继续编译我的程序,甚至没有在构建日志中显示该消息......至少可以说是令人不安的。
为什么会显示此消息?
为什么它不停止应用程序的编译和运行?
Vec2f的构造函数:
constexpr Vec2f::Vec2f(const float x, const float y) noexcept:
x(x),
y(y)
{
}
Run Code Online (Sandbox Code Playgroud)
物理组件构造函数:
constexpr PhysicsComponent::PhysicsComponent(Vec2f position, float mass, Vec2f momentum) noexcept:
current(position, mass, momentum),
previous(current),
interpolated(current)
{
}
Run Code Online (Sandbox Code Playgroud)
“current”、“previous”和“interpolated”三个数据成员的类型为PhysicsState,其构造函数详述如下
constexpr PhysicsState::PhysicsState(Vec2f position, …Run Code Online (Sandbox Code Playgroud) 我尝试在模板专用类中使用静态 constexpr 数组,如下所示:
///////////////////////////////////////////////////////////////////////////
struct good {
static constexpr int values[1] = { 0 };
};
constexpr int good::values[1];
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct bad;
template <>
struct bad<int> {
static constexpr int values[1] = { 0 };
};
constexpr int bad<int>::values[1];
///////////////////////////////////////////////////////////////////////////
int
main (int argc, char **argv)
{
#if 1
return good::values[0];
#else
return bad<int>::values[0];
#endif
}
Run Code Online (Sandbox Code Playgroud)
我知道声明和定义静态成员的要求,并且上面的“好”情况似乎使用 -std=c++1z 在 gcc-6.2.0 和 clang-3.9.0 上取得了成功。
然而,“坏”情况会导致 clang-3.9.0 下出现未定义的引用,输出如下:
danny@steve ~/src $ clang++ -std=c++1z scratch.cpp
/tmp/scratch-56fa44.o: In function `main':
scratch.cpp:(.text+0x15): …Run Code Online (Sandbox Code Playgroud) 是否允许将非常量引用声明为constexpr?示例代码:
int x = 1;
constexpr int& r = x;
Run Code Online (Sandbox Code Playgroud)
gcc 和 clang 都接受了这一点(我尝试了两者的几个当前和过去版本,回到 C++11,并且都接受了)。但是我认为它不应该被接受,因为 C++14 [dcl.constexpr/9] 说:
如果在引用声明中使用 constexpr 说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式
并且x不是常量表达式。
[dcl.constexpr] 的最新 C++17 草案中的语言发生了变化,甚至不再constexpr明确提及引用,我无法弄清楚它试图对它们说些什么。
我这里有一个 CRTP 模板类:
template <typename S>
class Base
{
public:
constexpr static S NOT_SET{0};
};
struct Derived : public Base<Derived>
{
};
Run Code Online (Sandbox Code Playgroud)
Clang (5.0.0) 不接受这一点:
5 : <source>:5:24: error: constexpr variable cannot have non-literal type 'const Derived'
constexpr static S NOT_SET{0};
^
8 : <source>:8:25: note: in instantiation of template class 'Base<Derived>' requested here
struct Derived : public Base<Derived>
^
5 : <source>:5:24: note: incomplete type 'const Derived' is not a literal type
constexpr static S NOT_SET{0};
^
8 : …Run Code Online (Sandbox Code Playgroud) 我最近在使用 constexpr 但我刚刚意识到我用错了它。我很好奇是否可以创建编译时变量(或变量对象)。cppreference.com
的 constexpr 定义告诉我们:
constexpr 说明符声明可以在编译时计算函数或变量的值。
那么为什么下面的代码不正确呢?
#include <iostream>
int main()
{
constexpr int x = 30;
x += 10;
std::cout << x;
}
Run Code Online (Sandbox Code Playgroud)
这个整数可以在编译时完美地求值。我知道编译器可以在没有 constexpr 修饰符的情况下优化这样的变量,但是如果我想要一个编译时对象怎么办?
#include <iostream>
class ctFoo {
public:
ctFoo()
: value{ 0 }
{
}
int accumulate(int value_) {
return (value += value_), value;
}
int value;
};
int main()
{
ctFoo foo;
std::cout << foo.accumulate(100);
}
Run Code Online (Sandbox Code Playgroud)
我有什么确定性可以确定该代码将在编译时进行评估?我问这个问题是因为我目前正在编写一些 Vector2 和 Vector3 数学,并且我想创建这样的实现,它将能够处理编译时和运行时计算。有可能吗?
谢谢。
正如 max66 指出的那样,constexpr 意味着 const,但我要问:为什么会这样?现代编译器应该能够在编译时推断出它的值。另外,我知道我可以简单地创建另一个 constexpr 常量(广告最上面的代码示例),但我的问题涉及更复杂的代码。
我有一个数学函数,我希望能够接受双精度数或双精度数数组/向量/容器,并且行为略有不同。
\n\n我正在尝试使用 SFINAE 和类型特征来选择正确的函数。
\n\n这是一个最小的例子:
\n\n#include <iostream>\n#include <vector>\n#include <type_traits>\n\ntemplate <typename T>\nconstexpr bool Iscontainer()\n{\n if constexpr (std::is_class<T>::value && std::is_arithmetic<typename T::value_type>::value) {\n return true;\n }\n return false;\n}\n\n// Function 1 (double):\ntemplate <typename T>\ntypename std::enable_if<std::is_arithmetic<T>::value>::type g(T const & t)\n{\n std::cout << "this is for a double" << t << std::endl;\n}\n\n// Function 2 (vec), version 1:\ntemplate <typename T>\ntypename std::enable_if<IsContainer<T>()>::type g(T const & t)\n{\n std::cout << "this is for a container" << t[0] << std::endl;\n}\n\nint main()\n{\n std::vector<double> v {1, 2};\n std::array<double, 2> a …Run Code Online (Sandbox Code Playgroud) Clang 接受这一点,但 GCC 不接受:
struct inner {int x;};
constexpr struct outer {inner i;} o{};
// definition of x4 results in GCC error:
// "accessing value of 'o' through a 'const int' glvalue in a constant expression"
constexpr int x1 { &(o.i)->*(&inner::x)}; // ok
constexpr int x2 { (&o->*(&outer::i)).x }; // ok
int x3 {&(&o->*(&outer::i))->*(&inner::x)}; // ok
constexpr int x4 {&(&o->*(&outer::i))->*(&inner::x)}; // error
Run Code Online (Sandbox Code Playgroud)
GCC 9.4 错误消息是
error: accessing value of 'o' through a 'const int' glvalue in a constant expression
Run Code Online (Sandbox Code Playgroud)
constexpr …
我有以下代码来测试我的 constexpr 可构造惰性类:
#include <optional>
template <class T>
class Lazy
{
using initializer_t = T (*)();
std::optional<T> m_val = std::nullopt;
initializer_t m_initializer;
public:
constexpr Lazy(initializer_t initializer = initializer_t{[] { return T{}; }}) noexcept
: m_initializer{initializer} {}
T& operator*()
{
if (!m_val.has_value()) {
m_val = m_initializer();
}
return *m_val;
}
constexpr T* operator->() { return &(**this); }
};
#include <iostream>
struct A {
int f() { return 10; }
~A()
{
std::cout << "Goodbye A " << (void*)this << std::endl; …Run Code Online (Sandbox Code Playgroud) 以下最小示例因未初始化数组数据成员而被 Clang 和 GCC 拒绝:
class vector3
{
public:
constexpr vector3() = default;
private:
float m_data[3];
};
constexpr auto vec = vector3{};
Run Code Online (Sandbox Code Playgroud)
这产生了合理的直接错误:
<source>:4:15: error: explicitly defaulted function 'constexpr vector3::vector3()' cannot be declared 'constexpr' because the implicit declaration is not 'constexpr':
4 | constexpr vector3() = default;
| ^~~~~~~
<source>:6:11: note: defaulted default constructor does not initialize 'float vector3::m_data [3]'
6 | float m_data[3];
| ^~~~~~
Run Code Online (Sandbox Code Playgroud)
上面代码的目标是确保vector3可以通过值初始化(例如vector3{})在常量表达式中使用,这将对子元素(m_data)进行零初始化。
错误是由于使用了constexpr关键字而发生的,修复方法只是删除关键字并允许default正确推断是否可以在常量表达式中使用: …