使用用户定义的转换运算符的函数模板重载决策
function template overload resolution with user defined conversion operator
根据 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&)
案例一
VS2015 选择模板版本,而 gcc 和 clang 选择非模板版本。
案例二
所有三个编译器都选择模板版本。
我们如何参考 C++ 11 标准来解释这种行为?
MSVC 错误。这里的行为取决于目标类型是否是引用类型,这会影响候选函数集。
在一个对象(A<int> objA = objP;
)的复制初始化中,适用[dcl.init]/17 says that the destination type is A<int>
and the candidate set is governed by [over.match.copy]中的规则,在其规则下它包括两个转换函数;他们打成平手,template/non-template 决胜局选择非模板。
在初始化一个引用const A<int>&
(operator=
的参数)时,[dcl.init.ref]/5 applies, which says that you first do overload resolution with a candidate set specified by [over.match.ref],在初始化一个对象的左值引用时,只包含转换函数返回引用。
因此在这种情况下唯一的候选者是模板;它被证明是可行的并被选中。甚至不考虑非模板。
这也意味着 A<int> objA(objP);
将使用模板,因为您在那里对 A<int>
的构造函数进行重载解析,并将尝试初始化 const A<int>&
参数 A<int>
的拷贝构造函数。
根据 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&)
案例一
VS2015 选择模板版本,而 gcc 和 clang 选择非模板版本。
案例二
所有三个编译器都选择模板版本。
我们如何参考 C++ 11 标准来解释这种行为?
MSVC 错误。这里的行为取决于目标类型是否是引用类型,这会影响候选函数集。
在一个对象(
A<int> objA = objP;
)的复制初始化中,适用[dcl.init]/17 says that the destination type isA<int>
and the candidate set is governed by [over.match.copy]中的规则,在其规则下它包括两个转换函数;他们打成平手,template/non-template 决胜局选择非模板。在初始化一个引用
const A<int>&
(operator=
的参数)时,[dcl.init.ref]/5 applies, which says that you first do overload resolution with a candidate set specified by [over.match.ref],在初始化一个对象的左值引用时,只包含转换函数返回引用。因此在这种情况下唯一的候选者是模板;它被证明是可行的并被选中。甚至不考虑非模板。
这也意味着 A<int> objA(objP);
将使用模板,因为您在那里对 A<int>
的构造函数进行重载解析,并将尝试初始化 const A<int>&
参数 A<int>
的拷贝构造函数。