函数模板重载决策与用户定义的转换运算符

时间:2016-05-06 06:12:43

标签: c++ c++11 overloading language-lawyer

根据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标准来解释这种行为?

1 个答案:

答案 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}}参数复制构造函数。