【问题标题】:Get full name of C++ class member variable [duplicate]获取C++类成员变量的全名[重复]
【发布时间】:2021-09-05 07:50:37
【问题描述】:

假设我有以下课程

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() 方法在编译时“自动生成”。

谢谢!

【问题讨论】:

标签: c++ c++17


【解决方案1】:

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&lt;char, L+1&gt; 中。

【讨论】:

  • 用户正在寻找编译时解决方案,该函数可以标记为 constexpr 吗?
  • @AlessandroTeruzzi 我已经设法拼凑了一些东西,但这肯定不是我希望在生产代码中看到的东西。
  • @AlessandroTeruzzi 这是基于__PRETTY_FUNCTION__ 的相同方法,采用更适合生产的形式:stackoverflow.com/questions/1055452/…
  • @Frank 你什么意思?我计算偏移量。
  • @HolyBlackCat 哦,我知道里面发生了什么。是的,这也应该适用于这种情况(使用占位符结构类型而不是 int)。感谢您的标注。我在快速阅读时错过了那部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-25
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 2018-11-15
  • 1970-01-01
相关资源
最近更新 更多