我有一个指针结构,其中的指针是任意类型的,但在编译时是已知的。
struct ptrs
{
int* a;
const char** b;
int* c;
float* d;
};
鉴于它们都是指针,它们的长度都相同。有没有办法可以访问带有类型信息的第 n 个元素。
我可以将结构转换为空指针数组,但随后我将不知道我在看什么类型,同样使用联合。
整个代码库都在 c++20 中,所以我不需要担心 c 支持。
编辑:我想要这个用于以下用途。我将创建一个可变参数宏来将任意数量的输入转换为指向 then 的指针数组。这将传递给处理函数,该函数将根据命令字符串以任意顺序处理它们。例如。 “返回 $var1 + $var2”。处理需要随机访问元素一次或多次,因此“索引”一个结构。但是为了支持算术,需要知道类型。
答案 0 :(得分:6)
是的,可以做到。有些代码编写起来有点棘手,但 Boost PFR 已经完成了繁重的工作,因此您可以执行以下操作:
ptrs p;
float * f = boost::pfr::get<3>(p); // get the `float *` member
*f = 123.4f; // and write via the pointer
[请注意,我只将其分成两行,以便我可以对每个步骤进行评论——像 *boost::pfr::get<3>(p) = 123.4f;
这样的内容也应该没问题。]
对于任何关心的人来说,你如何做到这一点的基本思想相当很简单——只是细节变得棘手。
基本方法是使用结构化绑定来获取您关心的项目。棘手的地方有几个:你不知道你在处理什么类型,而且类型各不相同,所以它不像创建一个项目数组并索引到数组那么简单。>
但是,尽管简化了很多,我们可以做这样的事情:
template <std::size_t index>
constexpr auto& get(auto& your_struct)
{
auto& [zero, one, two, three] = your_struct;
if constexpr (index == 0)
return zero;
if constexpr (index == 1)
return one;
if constexpr (index == 2)
return two;
return three;
}
我再说一遍:我正在简化相当多的内容(例如,我刚刚使用了固定数量的成员),但这至少是大致的总体思路——使用结构化绑定来获取成员,并使用 constexpr条件来选择你关心的哪一个,基本上所有的部分都有模板参数(以 auto
的形式),这样你就可以处理碰巧在那里的任何类型。
哦,还有一个有点难以处理的细节:就目前而言,这种实现只能适用于一种类型。也就是说,如果您尝试使用 get<0>
和 get<3>
,您将收到关于推导返回类型不一致的错误。因此,就目前而言,您可以使用 get<0>
或 get<2>
(或其他),但不能同时使用,因此这纯粹是概念的有限证明,而不是实际实现(完全)。
不过,这是一个有效的演示程序:
#include <cstddef>
#include <iostream>
struct ptrs {
int* a;
const char** b;
int* c;
float* d;
};
template <std::size_t index>
constexpr auto& get(auto& your_struct)
{
auto& [zero, one, two, three] = your_struct;
if constexpr (index == 0)
return zero;
if constexpr (index == 1)
return one;
if constexpr (index == 2)
return two;
return three;
}
int main() {
ptrs p;
p.d = new float; // `get<3>(p) = new float;` works fine too.
*get<3>(p) = 123.4;
// show we're accessing the same data either way:
std::cout << *get<3>(p) << "\t" << *(p.d) << "\n";
// type information is retained. For example, if we try to do this:
// get<3>(p) = new int; // <-- note int instead of float
// g++ 10 gives the error: "cannot convert ‘int*’ to ‘float*’ in assignment"
}
答案 1 :(得分:0)
这是唯一的方法,不用编造一堆元数据机制。
void* get(ptrs const& data, int n)
{
// TODO: add checks
return ((void**)&data)[n];
}
您应该注意,该标准并不能保证所有数据指针的大小都相同。但是,在大多数架构上,它们是。因此,请查阅您的编译器文档,或使用 static_assert
进行确认。