假设我有以下类(class)
namespace example {
class Test {
public:
int a;
};
};
这个变量的全范围名称将是“example::Test::a”
我的问题是,是否有某种方法可以在编译时 获取此信息并将其放入类中 的字符串中?例如,我希望结果等同于:
namespace example {
class Test {
public:
int a;
static const char* a_name() { return "example::Test::a"; }
};
};
其中 a_name() 方法是在编译时“自动生成”的。
谢谢!
a
的名称如果不使用非 C++ 正式组成部分的功能,则无法以任何方式访问它本身。如果您想保持符合标准,您别无选择,只能手动填写该部分。
除此之外,如果您有权访问 <cxxabi.h>
, 剩下的可以填typeid()
和 abi::__cxa_demangle
,但到那时,您将不得不在运行时开始连接字符串,这不是很好,但它确实让您接近您想要的位置。
#include <typeinfo>
#include <string>
#include <iostream>
#include <memory>
#include <cxxabi.h>
template<typename T>
std::string member_name(const char* name) {
int status = 0;
auto type_name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
// Feel free to return an error string instead of throwing an exception, obviously...
if(status != 0) throw std::runtime_error("failed to lookup type name");
std::unique_ptr<char, void(*)(void*)> cleanup(type_name, std::free);
return std::string(type_name) + "::a";
}
namespace example {
class Test {
public:
int a;
static std::string a_name() {
return member_name<Test>("a");
}
};
}
int main() {
std::cout << example::Test::a_name() << "\n";
}
编辑:
如果您愿意跳出标准 C++ 的界限,那么您可以使用特定于编译器的宏和一些 constexpr 来处理 std::string_view
在编译时获取成员名称。
这改编自 C++ Get name of type in template 中提供的解决方案(感谢@HolyBlackCat!)
#include <string_view>
#include <iostream>
namespace detail {
struct Placeholder {
int member;
};
template<auto T>
constexpr std::string_view raw_member_name() {
#ifdef _MSC_VER
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}
constexpr std::pair<std::size_t, std::size_t> member_name_offsets() {
std::string_view raw = raw_member_name<&Placeholder::member>();
std::string_view lookup = "detail::Placeholder::member";
auto leading = raw.find(lookup);
auto trailing = raw.size() - lookup.size();
return {leading, trailing};
}
}
template<auto T>
constexpr std::string_view member_name() {
constexpr auto offsets = detail::member_name_offsets();
std::string_view pretty = detail::raw_member_name<T>();
return pretty.substr(offsets.first, pretty.size() - offsets.second);
}
namespace example {
class Test {
public:
int a;
static constexpr auto a_name = member_name<&Test::a>();
};
}
int main() {
std::cout << example::Test::a_name << "\n"; // outputs: "example::Test::a"
}
如果您绝对必须有一个以 null 结尾的字符串,您还必须将字节复制到 std::array<char, L+1>
中。