标签: constexpr

用于编译时强制 constexpr 函数评估的单表达式助手可能吗?

@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不需要采用这种形式。

要求

  • 允许任何(数字本机)文字类型作为 constexpr 函数的输入。
    • 这也可以根据函数参数类型进行硬编码。
  • 允许任何(数字本机)文字类型作为输出,这是 constexpr 函数调用的结果。
    • 这也可以根据函数返回类型进行硬编码。

理想者

  • 减少宏的使用,但不要害怕使用。
  • 是通用的(不是硬编码的类型)。
  • 支持任何文字类型。最后,任何数字本机文字类型都是必需的。

相关问题:

  1. constexpr 函数何时在编译时进行求值?
  2. 强制在编译时计算常量表达式?
  3. 将任何函数作为模板参数传递?
  4. C++11 标准中的哪个位置指定了何时可以在翻译过程中计算 constexpr 函数?

相关代码示例的答案:

  • 1
  • 2
  • 3(这个有一个说明性的AT_COMPILATION宏)

所有代码示例都有关于要求的限制。

清楚地解释这在 C++ 中如何不可行也是一个很好的答案。

我怀疑这是不可能的,基于@K-ballo / @Herb Sutter 的 回答 …

c++ macros variadic-templates constexpr c++11

5
推荐指数
1
解决办法
3154
查看次数

错误:表达式必须具有常量值。对于一个明显恒定的值

我有一个非常简单的项目,它在 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)

c++ constexpr visual-studio-2015

5
推荐指数
1
解决办法
2848
查看次数

如何定义模板类专业化的静态 constexpr 数组成员

我尝试在模板专用类中使用静态 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)

c++ templates clang static-members constexpr

5
推荐指数
1
解决办法
356
查看次数

constexpr 对非常量对象的引用

是否允许将非常量引用声明为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明确提及引用,我无法弄清楚它试图对它们说些什么。

c++ reference language-lawyer constexpr c++14

5
推荐指数
1
解决办法
382
查看次数

clang vs gcc CRTP: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)

c++ gcc clang crtp constexpr

5
推荐指数
1
解决办法
1934
查看次数

C++ - 我可以创建编译时变量对象吗?

我最近在使用 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 常量(广告最上面的代码示例),但我的问题涉及更复杂的代码。

c++ variables compile-time constexpr

5
推荐指数
1
解决办法
7369
查看次数

使用 constexpr bool 测试的 enable_if 不起作用

我有一个数学函数,我希望能够接受双精度数或双精度数数组/向量/容器,并且行为略有不同。

\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)

c++ templates enable-if constexpr c++11

5
推荐指数
1
解决办法
2734
查看次数

通过指向成员的指针进行嵌套访问的编译时评估期间出现 GCC 错误

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 …

c++ gcc g++ constexpr

5
推荐指数
1
解决办法
71
查看次数

std::可选默认构造函数在 gcc 中不是 constexpr?

我有以下代码来测试我的 constexpr 可构造惰性类:

https://godbolt.org/z/rMLCiL

#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)

c++ gcc initialization constexpr stdoptional

5
推荐指数
1
解决办法
212
查看次数

`default` 构造函数在常量表达式中带有未初始化的成员

以下最小示例因未初始化数组数据成员而被 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)

Live Example

上面代码的目标是确保vector3可以通过值初始化(例如vector3{})在常量表达式中使用,这将对子元素(m_data)进行零初始化。

错误是由于使用了constexpr关键字而发生的,修复方法只是删除关键字并允许default正确推断是否可以在常量表达式中使用: …

c++ constexpr

5
推荐指数
1
解决办法
96
查看次数