我想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++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?如果是,有哪些差异以及在哪些场景下推荐使用哪种版本的声明?
我正在使用整洁的 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)
如何在保持编译时检查的同时恢复正常的函数调用语法?
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++类,其中某些成员变量仅在设置了模板标志时才存在。作为一个简单的例子,我们假设我想在性能敏感的计算中切换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类似以下 …
如何调用 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) 我想通过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++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) 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).
对于c++20,我们能得到的最接近 a 的是什么constexpr for (int i = 0; i < 5; ++i)?
给定一个函数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)