根据C ++ 11标准,以下代码的正确输出是什么?
#include <iostream>
template <typename X>
class A
{
public:
A()
{
std::cout << "A::A" << std::endl;
}
A(const A<X>&)
{
std::cout << "A::A(const A<X>&)" << std::endl;
}
A<X>& operator = (const A<X>&)
{
std::cout << "A::opeartor =(conat A&)" << std::endl;
return *this;
}
};
void* GetData()
{
// return data based on some condition
static A<int> a;
return &a;
}
class P
{
public:
template <typename T>
operator T&()
{
void* pData = GetData();
std::cout << "P::operator T&()" << std::endl;
return *(reinterpret_cast<T*>(pData));
}
operator A<int>()
{
std::cout << "P::opeartor A<int>" << std::endl;
return A<int>();
}
};
int main(int /*argc*/, char** /*argv*/)
{
P objP;
A<int> objA = objP; // case 1
objA = objP; // case 2
return 0;
}
clang和gcc产生以下输出。
P::opeartor A<int>
A::A
A::A
P::operator T&()
A::opeartor =(conat A&)
VS 2015生成输出,如下所示。
A::A
P::operator T&()
A::A(const A<X>&)
P::operator T&()
A::opeartor =(conat A&)
案例1
VS2015选择模板版本,其中gcc和clang选择非模板版本。
案例2
所有三个编译器都选择模板版本。
我们如何参考C ++ 11标准来解释这种行为?
答案 0 :(得分:3)
MSVC错了。此处的行为取决于目标类型是否为引用类型,这会影响候选函数集。
在对象(A<int> objA = objP;
)的复制初始化中,[dcl.init]/17中的适用规则表示目标类型为A<int>
,候选集由{{const A<int>&
管理3}},在其规则下,它包括两个转换函数;它们是绑定的,模板/非模板仲裁器选择非模板。
在初始化引用operator=
(A<int> objA(objP);
的参数)时,[over.match.copy]适用,表示您首先使用{{3指定的候选集进行重载解析当初始化对象的左值引用时,它只包含返回引用的转换函数。
因此,在这种情况下,唯一的候选人是模板;它证明是可行的并且被选中。非模板甚至不被考虑。
这也意味着A<int>
将使用该模板,因为您对const A<int>&
的构造函数执行了重载解析,并将尝试初始化A<int>
的{{1}}参数复制构造函数。