标签: constexpr

在编译时将函数指针转换为 std::uintptr_t

我想std::uintptr_t在编译时将常量表达式函数指针转换为 a 。我怎样才能做到这一点?

这是一个最小的例子:

#include <cstdint>
void fn() {}
int main(int argc, char** argv) {
  constexpr void* ptr = (void *) fn;
  constexpr std::uintptr_t idx = reinterpret_cast<std::uintptr_t>(fn);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

GCC 7/8/9 目前给出错误“std::uintptr_t在常量表达式中从指针类型转换为算术类型”。然而,我的理解是std::uintptr_t应该能够保存任何指针类型,这意味着这应该能够在常量表达式中完成。

背景

为了说明为什么我需要这个,我想(1)在编译时检索函数指针的地址,(2)将其转换为 a std::uintptr_t,然后(3)将其作为模板参数传递,以便它可以在编译时将其烘焙到函数中。

这是 RPC 引擎的一部分,类似于此代码,它会产生非常相似的错误:

#include <cstdio>
#include <cstdint>

template <std::uintptr_t FnPtr, typename Fn>
void fn_handler() {
  ((Fn *) FnPtr)();
}

int main(int argc, char** argv) {
  auto lel = []() {
    printf("Hi, fam!\n");
  };
  // Note that …
Run Code Online (Sandbox Code Playgroud)

c++ templates constexpr

3
推荐指数
1
解决办法
748
查看次数

静态 constexpr 全局变量

在 C++17 中,像这样声明全局常量有什么区别:

namespace ns
{
static constexpr const auto global_variable = 47;
}
Run Code Online (Sandbox Code Playgroud)

还指定const修饰符,并且:

namespace ns
{
static constexpr auto global_variable = 47;
}
Run Code Online (Sandbox Code Playgroud)

没有指定const?如果是,有哪些差异以及在哪些场景下推荐使用哪种版本的声明?

c++ static constants global-variables constexpr

3
推荐指数
1
解决办法
1597
查看次数

保持函数参数的保守性

我正在使用整洁的 fmt 库,该库在其版本 8 中会在编译时检查其格式字符串(如果编译器支持相关功能)。

在某些时候,我想编写以下代码:

throw my_exception("error: {}", 123);
Run Code Online (Sandbox Code Playgroud)

可悲的是,天真的实现:

struct my_exception : std::runtime_error {
  template<typename... Args>
  my_exception(Args&&... args)
    : std::runtime_error{fmt::format(std::forward<Args>(args)...)} 
  { }
};
Run Code Online (Sandbox Code Playgroud)

失败,因为这会失去字符串文字参数的“consteval-ness”,这是fmt::format. 目前,我决定以下几点:

template<std::size_t N>
struct literal {
  constexpr literal(const char (&str)[N]) noexcept {
    std::copy_n(str, N, this->str);
  }

  char str[N];
};

template<literal lit>
struct exception : std::runtime_error {
  template<typename... Args>
  exception(Args&&... args)
    : std::runtime_error{fmt::format(lit.str, std::forward<Args>(args)...)}
  {

  }
};
Run Code Online (Sandbox Code Playgroud)

被称为像

throw my_exception<"foo {}">(123);
Run Code Online (Sandbox Code Playgroud)

如何在保持编译时检查的同时恢复正常的函数调用语法?

c++ constexpr c++20 fmt consteval

3
推荐指数
1
解决办法
680
查看次数

从不求值为常量表达式的 lambda() 可以是 C++ 中的“constexpr”函数吗?

Lambdaoperator()隐式地constexpr根据https://en.cppreference.com/w/cpp/language/lambda

当此说明符 ( constexpr) 不存在时,函数调用运算符或任何给定的运算符模板特化将constexpr无论如何,如果它碰巧满足所有constexpr函数要求

constexpr以及根据https://en.cppreference.com/w/cpp/language/constexpr的 -function的要求

至少存在一组参数值,使得函数的调用可以是核心常量表达式的计算子表达式(对于构造函数,在常量初始值设定项中使用就足够了)(C++14 起)。违反此项目符号无需进行诊断。

在下一个示例中,该函数t()始终通过调用 lambda 引发异常l()

auto l = []()->bool { throw 42; };
constexpr bool t() { return l(); }
Run Code Online (Sandbox Code Playgroud)

GCC 拒绝此函数并出现错误:

call to non-'constexpr' function '<lambda()>'
Run Code Online (Sandbox Code Playgroud)

但 Clang 接受该程序(直到t()在不断的评估中使用该函数),这意味着它认为是l()一个constexpr函数,演示:https: //gcc.godbolt.org/z/j1z7ee3Wv

这是 Clang 中的错误,还是这样的编译器行为也是可以接受的?

c++ lambda language-lawyer constexpr

3
推荐指数
1
解决办法
167
查看次数

模板(去)激活的成员变量

我正在寻找一种方便的方法来创建一个C++类,其中某些成员变量仅在设置了模板标志时才存在。作为一个简单的例子,我们假设我想在性能敏感的计算中切换averageSum,即

struct Foo {
    // Some data and functions..
    
    void operator+=(const Foo& _other) {}
};



template<bool sumAverages>
class Calculator {
public:
    // Some member variables...
    
    // Those should only be present if sumAverages is true
    int count = 0;
    Foo resultSum;
    
    void calculate(/* some arguments */) {
        // Calculation of result...
        Foo result;
        
        // This should only be calculated if sumAverages is true
        ++count;
        resultSum += result;
        
        // Possibly some post processing...
    }
};
Run Code Online (Sandbox Code Playgroud)

一种方法是使用预处理器定义,但这些相当不方便,特别是如果我需要同一二进制文件中的两个版本。所以我正在寻找使用模板和if constexpr类似以下 …

c++ templates constexpr c++20

3
推荐指数
1
解决办法
128
查看次数

如何以 constexpr 方式调用具有元组输入的模板化静态类方法

如何调用 a ,以constexpr 方式static constexpr class::method (int i1, int i2, int i3)提供输入数据。tuple<int, int, int>

默认方法是使用std::apply将每个元组元素作为参数应用于函数。

一个最小的可视化示例,我试图实现的目标如下:

struct a {
    template <typename T>
    static constexpr void test(int i1, int i2, int i3) {
        // ...
    }
};

struct b : a {};
struct c {};

template <typename T>
struct test_functor {
    constexpr test_functor_t() {} // just for testing to express constexpr desire
    constexpr void operator()(auto... args) {
        T::test<c>(args...);
    }
};

constexpr std::tuple<int, int, int> tupl{ 1,2,3 …
Run Code Online (Sandbox Code Playgroud)

c++ constexpr c++20

3
推荐指数
1
解决办法
165
查看次数

如何通过标准元组操作正确转发和使用 constexpr 结构的嵌套元组

我想通过constexpr constructor a存储传递的数据struct,并将数据存储在 a 中std::tuple,以执行各种 TMP/编译时操作。

执行

template <typename... _Ts>
struct myInitializer {
    std::tuple<_Ts...> init_data;

    constexpr myInitializer(_Ts&&... _Vs) 
        : init_data{ std::tuple(std::forward<_Ts>(_Vs)...) }
    {}
};
Run Code Online (Sandbox Code Playgroud)

存储的数据使用轻量级strong type结构,通过左值和右值帮助器重载生成:

template <typename T, typename... Ts>
struct data_of_t {
    using type = T;
    using data_t = std::tuple<Ts...>;
    data_t data;

    constexpr data_of_t(Ts&&... _vs)
        : data(std::forward<Ts>(_vs)...)
    {}
};
template<typename T, typename... Ts>
constexpr auto data_of(Ts&&... _vs) {
    return data_of_t<T, Ts...>(std::forward<Ts>(_vs)...);
};

template<typename T, typename... Ts>
constexpr auto data_of(Ts&... _vs) { …
Run Code Online (Sandbox Code Playgroud)

c++ tuples variadic-templates constexpr c++20

3
推荐指数
1
解决办法
188
查看次数

C++20 consteval 函数和 constexpr 变量 - 是否保证在编译时计算它们?

在 C++20 中,我们有consteval声明立即函数的关键字。例如:

consteval int f(int x) { return x * x; }
Run Code Online (Sandbox Code Playgroud)

需要这样的函数来生成常量表达式。但是,根据标准,常量表达式不需要在编译时实际求值,除非它用在需要常量的地方,例如在模板参数中。例如,标准中似乎没有任何内容要求在编译时对其进行评估:

int a = f(10);
Run Code Online (Sandbox Code Playgroud)

然而,这些要求强烈表明立即函数应该在编译时进行评估。

标准中似乎也没有要求在编译时评估 constexpr 变量。所以即使我们创建变量constexpr,即

constexpr int a = f(10);
Run Code Online (Sandbox Code Playgroud)

它只断言这f(10)是一个常量表达式并生成a一个常量表达式(但同样,常量表达式不需要在编译时实际评估它们)。然而,就像以前一样,对 constexpr 变量的要求强烈表明它们应该在编译时进行评估。

只有constinit 变量的定义不同 - constinit 变量需要进行静态初始化,因此必须在编译时计算它们并直接嵌入到二进制文件中。然而,这个相关问题的答案说 constexpr 意味着 constinit,至少对于全局变量来说,这似乎与我上面写的内容相矛盾。

那么, consteval 函数和 constexpr 变量是否保证在编译时进行求值?


旁注:我的实际用例涉及尝试使用常量初始化结构中的字段,如下所示:

consteval int my_complicated_calculation() {
    // do complicated mathematics and return an int
}
struct A {
    int value;
    A() : value{my_complicated_calculation()} {}
}
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer constexpr c++20 consteval

3
推荐指数
1
解决办法
1417
查看次数

通过索引实现“constexpr for”

for (int i = 0; i < 5; ++i) {
    std::get<i>(tuple);
}
Run Code Online (Sandbox Code Playgroud)

这不会编译,因为i不是编译时常量。关于如何迭代 std::tuple 的元素?和其他帖子我看到了递归或使用的答案std::apply,但那些失去了索引控制。我也不想仅仅把自己限制在std::tuple


每当我必须在编译时循环某些内容时,我都必须停下来思考并做一些奇怪的事情,特别是当我尝试实现非标准迭代(例如反向、自定义增量)或在同一语句(例如std::get<i>(tuple) * std::get<i + 1>(tuple).


对于我们能得到的最接近 a 的是什么constexpr for (int i = 0; i < 5; ++i)

c++ for-loop constexpr c++20

3
推荐指数
1
解决办法
328
查看次数

为 constexpr std::array&lt;size_t,3&gt; 中的每个模板参数调用模板函数

给定一个函数print<size_t>(void)和 a ,我想要一个调用每个inconstexpr std::array<size_t,3> q={1,2,3}的循环。print<qi>qiq

我的最小示例如下所示:

#include<iostream>
#include<array>

template<size_t n>
void print(){ std::cout << n << "\n"; }

template< size_t N, const std::array<const size_t,N> q>
constexpr void print_long(){
    //
    // I) this is what I want to do
    for(size_t i=0;i<N;++i){ print<q[i]>(); }
    //
    // II) this does not compile either (because "it++")
    constexpr auto it = q.begin();
    while(it!=q.end()){ print<*(it++)>(); }
    //
    // III) for_each is no constexpr either
    std::for_each(q.begin(),q.end(),[](const auto& it){ print<it>(); }); …
Run Code Online (Sandbox Code Playgroud)

c++ for-loop compile-time function-templates constexpr

3
推荐指数
1
解决办法
116
查看次数