读完这个来源(以及我的答案)和这个来源后,我的印象是我们可以使用
std::source_location::function_name
来提取数据成员的名称。
假设我们有一些
struct_t
类型和 my_struct
实例。此外,以下属性对于 struct_t
有效:
auto& [a,b,c] = my_struct;
;Q:如何在没有其他库和std::source_location::function_name
的情况下使用C++20从
struct_t
中提取所有非静态数据成员名称?正确的答案应该很容易推广到任意数量的字段,并且与 g++、clang 和 MSVC 兼容。
下面的代码表明这个任务是很有可能的。但首先,它需要一个复制构造函数,并且与 MSVC 不兼容,这意味着它违反了 C++20 语言标准。您的答案可能会使用此代码作为起点,也可能根本不使用它
#include <iostream>
#include <type_traits>
#include <source_location>
#include <vector>
#include <string_view>
#include <array>
struct struct_t {
int field1;
double field2;
std::vector<int> field3;
};
template<void* p>
std::string_view get(){
return std::source_location::current().function_name();
}
template<class T>
auto fields3(T&& st){
static auto inst{std::forward<T>(st)};//bad. Needs a copy or move constructor
auto& [a,b,c]=inst;
return std::array{get<(void*)&a>(), get<(void*)&b>(), get<(void*)&c>()};
}
int main()
{
for (auto field:fields3(struct_t{})){
std::cout<<field<<"\n";
}
//std::string_view get() [p = &inst.field1]
//std::string_view get() [p = &inst.field2]
//std::string_view get() [p = &inst.field3]
return 0;
}
这里是链接库似乎采取的方法。基本策略似乎是将指针传递给已声明但从未定义的
static
成员对象的字段。因此,该对象从未被实际构造。不过,在这种非常特殊的情况下,访问此类对象的字段是可以的,所以是的,据我所知,这是符合标准的。
它是便携式的吗?不。这依赖于解析
std::source_location::current().function_name()
返回的字符串,该字符串是实现定义的,实际上可能包含也可能不包含传递给它的指针所指向的字段的名称。在 GCC 和 Clang 上确实如此;在 MSVC 上似乎没有。