c++ - 获取C++类成员变量全名

标签 c++ c++17

<分区>

假设我有以下类(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> 中。

关于c++ - 获取C++类成员变量全名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68071339/

相关文章:

C++如何使类类型更通用并将其用作一种接口(interface)

c++ - 无锁队列中的内存管理

c++ - G++ 7.1.0 及更高版本支持此构造函数中的保证复制省略,但 Clang++ 4.0 及更高版本不支持

c++ - 为什么自动返回类型在此示例中会丢失移动语义?

c++ - C++ 中的 Trie 实现

c++ - 是否可以在 Visual C++ 中默认禁用增量链接?

c++ - 在 C++17 中使用空列表初始化构造函数时出现编译错误

c++ - 视觉 C : Namespace Scope Bug or Obscure Feature?

c++ - 移除 std::future 和 std::promise 的无效特化

C++ 循环算法逻辑问题