如何轻松知道编译器选择了哪些特殊成员函数?
How to easily know which special member functions the compiler has chosen?
覆盖每个特殊成员函数的天真方法,并在每个函数的主体中插入 printf
或 cout
(例如 C++: Implicit Member Functions here on SO; Vandevoorde and Josuttis 称其为 "tracers"),不上诉:
- 侵入式,就代码库增量而言
- O(n),其中 n = |类|,根据工作量
- 可能的观察者效应
将 -E
(或 -save-temps
)提供给 g++ 会导致后者为每个源 .cpp
(或 .cxx
)文件发出一个 .ii
文件;在这样的 .ii
中,将使用 cpp
预处理器采取的确切步骤对源进行注释。理想情况下,我想要类似的东西,但源被注释为
Foo baz;
//// Line 55, choosing Foo::Foo(); implicit; empty body
Foo qux(Bar::mkFoo(42));
//// Line 56, choosing Foo::Foo(int)
//// Line 56, choosing Foo::Foo(const Foo&)
//// Line 56, choosing Foo::~Foo(); implicit
Foo qux2(std::move(Bar::mkFoo(4.2)));
//// Line 57, choosing Foo::Foo(double)
//// Line 57, choosing Foo::Foo(Foo&&)
//// Line 57, choosing Foo::~Foo(); implicit
理想的方法将显示为编译器提供的特定优化选项所做的选择。
有人知道用 g++ 实现这个期望的方法吗?我准备开始编写一个 g++ 插件,但想在重新发明这个特定的轮子之前先问一下。
如果有一种方法可以用 clang 做到这一点,那也很好。
非常感谢。
我猜你可以在 clang. clang provides several libraries providing access to the internal data structures used, including an AST 的基础上构建类似这样的东西。不过,AST 应该包含很多信息,而且感兴趣的内容可能并不明显。
例如,使用这个输入
struct foo {
foo();
explicit foo(int);
foo(foo&&);
foo(foo const&);
~foo();
};
struct bar {
static auto mkfoo(int x) -> foo;
};
template <typename T>
auto move(T&& t) -> T&&;
int main() {
foo f0;
foo f1{bar::mkfoo(17)};
foo f2{move(bar::mkfoo(17))};
}
使用内置命令转储AST,即使用命令行
clang -cc1 -std=c++11 -ast-dump ast.cpp
在下面产生以下输出。如果你仔细观察,你会看到你所追求的大部分操作。不过,您可能需要忽略您不感兴趣的细节。
TranslationUnitDecl 0x7fea3b82ccc0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fea3b82d200 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x7fea3b82d260 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x7fea3b82d620 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
|-CXXRecordDecl 0x7fea3b82d670 <ast.cpp:1:1, line:7:1> line:1:8 referenced struct foo definition
| |-CXXRecordDecl 0x7fea3b82d780 <col:1, col:8> col:8 implicit referenced struct foo
| |-CXXConstructorDecl 0x7fea3b82d8b0 <line:2:5, col:9> col:5 used foo 'void (void)'
| |-CXXConstructorDecl 0x7fea3b873260 <line:3:5, col:21> col:14 foo 'void (int)'
| | `-ParmVarDecl 0x7fea3b82d980 <col:18> col:21 'int'
| |-CXXConstructorDecl 0x7fea3b873420 <line:4:5, col:14> col:5 used foo 'void (struct foo &&)'
| | `-ParmVarDecl 0x7fea3b873360 <col:9, col:12> col:14 'struct foo &&'
| |-CXXConstructorDecl 0x7fea3b8735e0 <line:5:5, col:19> col:5 foo 'void (const struct foo &)'
| | `-ParmVarDecl 0x7fea3b873520 <col:9, col:18> col:19 'const struct foo &'
| `-CXXDestructorDecl 0x7fea3b8736f0 <line:6:5, col:10> col:5 used ~foo 'void (void) noexcept'
|-CXXRecordDecl 0x7fea3b8737e0 <line:9:1, line:11:1> line:9:8 struct bar definition
| |-CXXRecordDecl 0x7fea3b8738f0 <col:1, col:8> col:8 implicit struct bar
| `-CXXMethodDecl 0x7fea3b873af0 <line:10:5, col:33> col:17 used mkfoo 'auto (int) -> struct foo' static
| `-ParmVarDecl 0x7fea3b873990 <col:23, col:27> col:27 x 'int'
|-FunctionTemplateDecl 0x7fea3b873e70 <line:13:1, line:14:22> col:6 move
| |-TemplateTypeParmDecl 0x7fea3b873ba0 <line:13:11, col:20> col:20 referenced typename T
| |-FunctionDecl 0x7fea3b873dd0 <line:14:1, col:22> col:6 move 'auto (T &&) -> T &&'
| | `-ParmVarDecl 0x7fea3b873cc0 <col:11, col:15> col:15 t 'T &&'
| `-FunctionDecl 0x7fea3b8757b0 <col:1, col:22> col:6 used move 'auto (struct foo &&) -> struct foo &&'
| |-TemplateArgument type 'struct foo'
| `-ParmVarDecl 0x7fea3b8756b0 <col:11, col:15> col:15 t 'struct foo &&'
`-FunctionDecl 0x7fea3b873f10 <line:16:1, line:20:1> line:16:5 main 'int (void)'
`-CompoundStmt 0x7fea3b875a48 <col:12, line:20:1>
|-DeclStmt 0x7fea3b8740e0 <line:17:5, col:11>
| `-VarDecl 0x7fea3b874020 <col:5, col:9> col:9 f0 'struct foo' callinit
| `-CXXConstructExpr 0x7fea3b874078 <col:9> 'struct foo' 'void (void)'
|-DeclStmt 0x7fea3b875398 <line:18:5, col:27>
| `-VarDecl 0x7fea3b874110 <col:5, col:26> col:9 f1 'struct foo' listinit
| `-ExprWithCleanups 0x7fea3b875380 <col:9, col:26> 'struct foo'
| `-CXXConstructExpr 0x7fea3b875348 <col:9, col:26> 'struct foo' 'void (struct foo &&)' elidable
| `-MaterializeTemporaryExpr 0x7fea3b875330 <col:12, col:25> 'struct foo' xvalue
| `-CXXBindTemporaryExpr 0x7fea3b8752c8 <col:12, col:25> 'struct foo' (CXXTemporary 0x7fea3b8752c0)
| `-CallExpr 0x7fea3b875290 <col:12, col:25> 'struct foo'
| |-ImplicitCastExpr 0x7fea3b875278 <col:12, col:17> 'auto (*)(int) -> struct foo' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x7fea3b8741b8 <col:12, col:17> 'auto (int) -> struct foo' lvalue CXXMethod 0x7fea3b873af0 'mkfoo' 'auto (int) -> struct foo'
| `-IntegerLiteral 0x7fea3b875200 <col:23> 'int' 17
`-DeclStmt 0x7fea3b875a30 <line:19:5, col:33>
`-VarDecl 0x7fea3b8753c0 <col:5, col:32> col:9 f2 'struct foo' listinit
`-ExprWithCleanups 0x7fea3b875a18 <col:9, col:32> 'struct foo'
`-CXXConstructExpr 0x7fea3b8759e0 <col:9, col:32> 'struct foo' 'void (struct foo &&)'
`-CallExpr 0x7fea3b875950 <col:12, col:31> 'struct foo':'struct foo' xvalue
|-ImplicitCastExpr 0x7fea3b875938 <col:12> 'auto (*)(struct foo &&) -> struct foo &&' <FunctionToPointerDecay>
| `-DeclRefExpr 0x7fea3b8758b0 <col:12> 'auto (struct foo &&) -> struct foo &&' lvalue Function 0x7fea3b8757b0 'move' 'auto (struct foo &&) -> struct foo &&' (FunctionTemplate 0x7fea3b873e70 'move')
`-MaterializeTemporaryExpr 0x7fea3b875980 <col:17, col:30> 'struct foo':'struct foo' xvalue
`-CXXBindTemporaryExpr 0x7fea3b875558 <col:17, col:30> 'struct foo' (CXXTemporary 0x7fea3b875550)
`-CallExpr 0x7fea3b875518 <col:17, col:30> 'struct foo'
|-ImplicitCastExpr 0x7fea3b875500 <col:17, col:22> 'auto (*)(int) -> struct foo' <FunctionToPointerDecay>
| `-DeclRefExpr 0x7fea3b8754a8 <col:17, col:22> 'auto (int) -> struct foo' lvalue CXXMethod 0x7fea3b873af0 'mkfoo' 'auto (int) -> struct foo'
`-IntegerLiteral 0x7fea3b8754e0 <col:28> 'int' 17
覆盖每个特殊成员函数的天真方法,并在每个函数的主体中插入 printf
或 cout
(例如 C++: Implicit Member Functions here on SO; Vandevoorde and Josuttis 称其为 "tracers"),不上诉:
- 侵入式,就代码库增量而言
- O(n),其中 n = |类|,根据工作量
- 可能的观察者效应
将 -E
(或 -save-temps
)提供给 g++ 会导致后者为每个源 .cpp
(或 .cxx
)文件发出一个 .ii
文件;在这样的 .ii
中,将使用 cpp
预处理器采取的确切步骤对源进行注释。理想情况下,我想要类似的东西,但源被注释为
Foo baz;
//// Line 55, choosing Foo::Foo(); implicit; empty body
Foo qux(Bar::mkFoo(42));
//// Line 56, choosing Foo::Foo(int)
//// Line 56, choosing Foo::Foo(const Foo&)
//// Line 56, choosing Foo::~Foo(); implicit
Foo qux2(std::move(Bar::mkFoo(4.2)));
//// Line 57, choosing Foo::Foo(double)
//// Line 57, choosing Foo::Foo(Foo&&)
//// Line 57, choosing Foo::~Foo(); implicit
理想的方法将显示为编译器提供的特定优化选项所做的选择。
有人知道用 g++ 实现这个期望的方法吗?我准备开始编写一个 g++ 插件,但想在重新发明这个特定的轮子之前先问一下。
如果有一种方法可以用 clang 做到这一点,那也很好。
非常感谢。
我猜你可以在 clang. clang provides several libraries providing access to the internal data structures used, including an AST 的基础上构建类似这样的东西。不过,AST 应该包含很多信息,而且感兴趣的内容可能并不明显。
例如,使用这个输入
struct foo {
foo();
explicit foo(int);
foo(foo&&);
foo(foo const&);
~foo();
};
struct bar {
static auto mkfoo(int x) -> foo;
};
template <typename T>
auto move(T&& t) -> T&&;
int main() {
foo f0;
foo f1{bar::mkfoo(17)};
foo f2{move(bar::mkfoo(17))};
}
使用内置命令转储AST,即使用命令行
clang -cc1 -std=c++11 -ast-dump ast.cpp
在下面产生以下输出。如果你仔细观察,你会看到你所追求的大部分操作。不过,您可能需要忽略您不感兴趣的细节。
TranslationUnitDecl 0x7fea3b82ccc0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fea3b82d200 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x7fea3b82d260 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x7fea3b82d620 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
|-CXXRecordDecl 0x7fea3b82d670 <ast.cpp:1:1, line:7:1> line:1:8 referenced struct foo definition
| |-CXXRecordDecl 0x7fea3b82d780 <col:1, col:8> col:8 implicit referenced struct foo
| |-CXXConstructorDecl 0x7fea3b82d8b0 <line:2:5, col:9> col:5 used foo 'void (void)'
| |-CXXConstructorDecl 0x7fea3b873260 <line:3:5, col:21> col:14 foo 'void (int)'
| | `-ParmVarDecl 0x7fea3b82d980 <col:18> col:21 'int'
| |-CXXConstructorDecl 0x7fea3b873420 <line:4:5, col:14> col:5 used foo 'void (struct foo &&)'
| | `-ParmVarDecl 0x7fea3b873360 <col:9, col:12> col:14 'struct foo &&'
| |-CXXConstructorDecl 0x7fea3b8735e0 <line:5:5, col:19> col:5 foo 'void (const struct foo &)'
| | `-ParmVarDecl 0x7fea3b873520 <col:9, col:18> col:19 'const struct foo &'
| `-CXXDestructorDecl 0x7fea3b8736f0 <line:6:5, col:10> col:5 used ~foo 'void (void) noexcept'
|-CXXRecordDecl 0x7fea3b8737e0 <line:9:1, line:11:1> line:9:8 struct bar definition
| |-CXXRecordDecl 0x7fea3b8738f0 <col:1, col:8> col:8 implicit struct bar
| `-CXXMethodDecl 0x7fea3b873af0 <line:10:5, col:33> col:17 used mkfoo 'auto (int) -> struct foo' static
| `-ParmVarDecl 0x7fea3b873990 <col:23, col:27> col:27 x 'int'
|-FunctionTemplateDecl 0x7fea3b873e70 <line:13:1, line:14:22> col:6 move
| |-TemplateTypeParmDecl 0x7fea3b873ba0 <line:13:11, col:20> col:20 referenced typename T
| |-FunctionDecl 0x7fea3b873dd0 <line:14:1, col:22> col:6 move 'auto (T &&) -> T &&'
| | `-ParmVarDecl 0x7fea3b873cc0 <col:11, col:15> col:15 t 'T &&'
| `-FunctionDecl 0x7fea3b8757b0 <col:1, col:22> col:6 used move 'auto (struct foo &&) -> struct foo &&'
| |-TemplateArgument type 'struct foo'
| `-ParmVarDecl 0x7fea3b8756b0 <col:11, col:15> col:15 t 'struct foo &&'
`-FunctionDecl 0x7fea3b873f10 <line:16:1, line:20:1> line:16:5 main 'int (void)'
`-CompoundStmt 0x7fea3b875a48 <col:12, line:20:1>
|-DeclStmt 0x7fea3b8740e0 <line:17:5, col:11>
| `-VarDecl 0x7fea3b874020 <col:5, col:9> col:9 f0 'struct foo' callinit
| `-CXXConstructExpr 0x7fea3b874078 <col:9> 'struct foo' 'void (void)'
|-DeclStmt 0x7fea3b875398 <line:18:5, col:27>
| `-VarDecl 0x7fea3b874110 <col:5, col:26> col:9 f1 'struct foo' listinit
| `-ExprWithCleanups 0x7fea3b875380 <col:9, col:26> 'struct foo'
| `-CXXConstructExpr 0x7fea3b875348 <col:9, col:26> 'struct foo' 'void (struct foo &&)' elidable
| `-MaterializeTemporaryExpr 0x7fea3b875330 <col:12, col:25> 'struct foo' xvalue
| `-CXXBindTemporaryExpr 0x7fea3b8752c8 <col:12, col:25> 'struct foo' (CXXTemporary 0x7fea3b8752c0)
| `-CallExpr 0x7fea3b875290 <col:12, col:25> 'struct foo'
| |-ImplicitCastExpr 0x7fea3b875278 <col:12, col:17> 'auto (*)(int) -> struct foo' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x7fea3b8741b8 <col:12, col:17> 'auto (int) -> struct foo' lvalue CXXMethod 0x7fea3b873af0 'mkfoo' 'auto (int) -> struct foo'
| `-IntegerLiteral 0x7fea3b875200 <col:23> 'int' 17
`-DeclStmt 0x7fea3b875a30 <line:19:5, col:33>
`-VarDecl 0x7fea3b8753c0 <col:5, col:32> col:9 f2 'struct foo' listinit
`-ExprWithCleanups 0x7fea3b875a18 <col:9, col:32> 'struct foo'
`-CXXConstructExpr 0x7fea3b8759e0 <col:9, col:32> 'struct foo' 'void (struct foo &&)'
`-CallExpr 0x7fea3b875950 <col:12, col:31> 'struct foo':'struct foo' xvalue
|-ImplicitCastExpr 0x7fea3b875938 <col:12> 'auto (*)(struct foo &&) -> struct foo &&' <FunctionToPointerDecay>
| `-DeclRefExpr 0x7fea3b8758b0 <col:12> 'auto (struct foo &&) -> struct foo &&' lvalue Function 0x7fea3b8757b0 'move' 'auto (struct foo &&) -> struct foo &&' (FunctionTemplate 0x7fea3b873e70 'move')
`-MaterializeTemporaryExpr 0x7fea3b875980 <col:17, col:30> 'struct foo':'struct foo' xvalue
`-CXXBindTemporaryExpr 0x7fea3b875558 <col:17, col:30> 'struct foo' (CXXTemporary 0x7fea3b875550)
`-CallExpr 0x7fea3b875518 <col:17, col:30> 'struct foo'
|-ImplicitCastExpr 0x7fea3b875500 <col:17, col:22> 'auto (*)(int) -> struct foo' <FunctionToPointerDecay>
| `-DeclRefExpr 0x7fea3b8754a8 <col:17, col:22> 'auto (int) -> struct foo' lvalue CXXMethod 0x7fea3b873af0 'mkfoo' 'auto (int) -> struct foo'
`-IntegerLiteral 0x7fea3b8754e0 <col:28> 'int' 17