在 c++ 中显示嵌套类型定义的最基本类型声明

Show most basic type declaration of nested typedefs in c++

本文关键字:类型 声明 定义 c++ 显示 嵌套类型      更新时间:2023-10-16

在读取别人的代码时,除了遍历所有标头,搜索各自的定义之外,是否有一种简单的方法来展开嵌套typedef的底层类型?

例如,今天我遇到了

auto* p = new A<B::C>();

其中 B::C 在某个标头中定义为

template <typename T>
class B: public BBase {
    typedef B< D<E, E> > C;
}

D 和 E 在其他地方定义。C

我可以以某种方式显示 p 实际上是A<B<D<E, E>>>吗?

如果您不想混淆typeid名称,另一种方法是:

template<typename> struct TC;

然后TC<A<B::C>> a;放在某个地方,你会得到一个编译器错误,其中包含完整的推断类型。

例如:

template<typename> struct TC;
template<typename> using A = int;
using B = A<float>;
int main()
{
    TC<B> a;
}

海湾合作委员会输出:

主.cpp:8:11: 错误: 聚合TC<int> a具有不完整的类型,无法定义

如您所见,B被替换为A<float>,后者在编译器错误中被替换为int

您可以使用

typeid(T).name() .它在 Visual C++ 中为您提供了一个很好的可读类型声明。使用 g++ 编译器,您必须使用 g++ 特定的功能来解散有点神秘的结果。

为了使用typeid必须包含<typeinfo>标头。

g++ 名称拆解函数是从 g++ <cxxabi.h> 标头abi::__cxa_demangle的。


示例(我必须修复您所谓的声明的各种细节):

template< class > struct A {};
template<class, class> struct D {};
struct E {};
struct BBase {};
template<class>
class B: public BBase
{
public:
    using C = B< D<E, E> >;
};
#include <string>
#include <typeinfo>
using namespace std;
#ifdef __GNUC__
#   include <cxxabi.h>
    auto demangled( char const* name )
        -> string
    {
        int status = 0;
        char* realname = abi::__cxa_demangle( name, 0, 0, &status );
        string result = realname;
        free( realname );
        return result;
    }
#else
#   include <sstream>
    auto demangled( char const* name )
        -> string
    {
        // Possibly remove all instances of "struct ", "class " and "enum "
        return name;
    }
#endif
#include <iostream>
auto main() -> int
{
    auto* p = new A<B<int>::C>();
    (void) p;  // unused
    cout << demangled( typeid( p ).name() ) << endl;
}

使用 g++ 输出:

A<E,>>>*

另一种方法是TartanLlama提出的技巧,即在未定义的模板中使用相关类型:

template<class> class Incomplete;
auto main() -> int
{
    Incomplete< A<B<int>::C> > x;
}

使用 g++ 生成错误消息:

ar.cpp:24:36:错误:聚合"不完整<E,E>>>> x"具有不完整的类型,无法定义        不完整::C>> x;                                   ^

这些是我想到的选项:

1)调试打印,可以临时添加typeid(E)等,但需要编译运行,所以不只是读取代码。

2)使用像Visual Studio,qt creator等IDE应该能够显示实际的typedefs/定义,当鼠标悬停在typedef/defines的任何用法上时。

3)使用文本编辑器

,许多文本编辑器可能允许使用插件来加快搜索速度,并从符号跳转到符号以快速找到它们已定义的内容。

所以最终的答案我认为通过查看代码是没有办法知道的,这实际上是定义带来的一个问题,它稍微混淆了代码。

on gcc/clang:

#include <iostream>
#include <cxxabi.h>
#include <string>
#include <stdexcept>
#include <exception>
#include <typeinfo>
std::string demangle(const char* mangled_name)
{
    using namespace std;
    size_t len = 0;
    int stat = 0;
    struct deleter {
        void operator()(const char* p) const {
            if (p) {
                auto p1 = const_cast<char*>(p);
                free(p1);
            }
        }
    };
    using ptr_type = std::unique_ptr<const char, deleter>;
    auto pname = ptr_type(abi::__cxa_demangle(mangled_name,
                                              nullptr,
                                              &len,
                                              &stat),
                          deleter());
    if (stat)
    {
        switch(stat) {
            case -1:
                throw std::bad_alloc();
                break;
            case -2:
                throw std::logic_error("invalid name: "s + mangled_name);
                break;
            case -3:
                throw std::invalid_argument("demangle");
            default:
                throw std::logic_error("unknown error code "s + to_string(stat));
        }
    }
    return string(pname.get(), len);
}
template<class X, class Y> struct D {};
struct E {};
template <typename T>
struct B {
    typedef B< D<E, E> > C;
};
int main()
{
    using namespace std;
    cout << demangle(typeid(B<int>::C).name()) << endl;
    return 0;
}

毫无疑问,Windows将具有类似的方法来解开名称。

预期输出:

B<D<E, E> >