我试图理解为什么除非添加括号,否则以下代码段的替换会失败:
template<typename T>
struct A {};
template<typename T>
struct B {
B(A<T>);
};
template<typename T>
void example(A<T>, B<T>);
struct C {};
struct D {
D(C);
};
void example2(C, D);
int main(int argc, char *argv[]) {
example(A<int>{}, A<int>{}); // error
example(A<int>{}, {A<int>{}}); // ok
example2(C{}, C{}); // ok
example2(C{}, {C{}}); // ok
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请参阅此示例:https : //godbolt.org/z/XPqHww
因为example2我能够将 隐式传递C{}给 的构造函数而D没有任何错误。因为example我不允许隐式传递A<int>{}直到我添加括号。
什么定义了这种行为?
该A()宏只会在 MSVC 上扩展,而不会在 GCC/Clang 上扩展,除非A()带有前缀,例如Test A().
通过在-E( /E) 标志 ( Godbolt.org )下运行以下代码段:
#define A() HelloWorld::
#define B() ::
A()
B()
Run Code Online (Sandbox Code Playgroud)
我们看到 MSVC 给出了以下输出:
HelloWorld::
::
Run Code Online (Sandbox Code Playgroud)
而 GCC/Clang 给出了不同的输出:
::
Run Code Online (Sandbox Code Playgroud)
但是然后运行这个片段:
#define A() HelloWorld::
A()
Test A()
Run Code Online (Sandbox Code Playgroud)
在所有 3 个编译器上为我们提供以下信息:
HelloWorld::
Test HelloWorld::
Run Code Online (Sandbox Code Playgroud)
为什么 GCC/Clang 输出缺少第一行?为什么它在Test A()写入时正确扩展所有事件?这是在标准中明确定义的,还是特定于编译器的?