Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function template overload resolution with user defined conversion operator

What is the correct output for following code according to C++11 standard?

#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 and gcc produce following output.

P::opeartor A<int>
A::A
A::A
P::operator T&()
A::opeartor =(conat A&)

VS 2015 generates output as shown below.

A::A
P::operator T&()
A::A(const A<X>&)
P::operator T&()
A::opeartor =(conat A&)

Case 1

VS2015 picks template version where as gcc and clang picks non template version.

Case 2

All three compilers pick template version.

How can we explain this behavior with reference to C++ 11 standard?

like image 599
C17 Avatar asked Apr 19 '26 07:04

C17


1 Answers

MSVC is wrong. The behavior here depends on whether the destination type is a reference type, which affects the set of candidate functions.

  • In copy-initialization of an object (A<int> objA = objP;), the applicable rules in [dcl.init]/17 says that the destination type is A<int> and the candidate set is governed by [over.match.copy], under whose rules that it includes both conversion functions; they are tied, and the template/non-template tiebreaker selects the non-template.

  • In initializing a reference const A<int>& (the parameter of operator=), [dcl.init.ref]/5 applies, which says that you first do overload resolution with a candidate set specified by [over.match.ref], which, when initializing an lvalue reference to object, includes only conversion function returning references.

    Thus in this case the only candidate is the template; it proves viable and is selected. The non-template isn't even considered.

This also means that A<int> objA(objP); will use the template, because there you do overload resolution on the constructors of A<int>, and will be trying to initialize the const A<int>& parameter of A<int>'s copy constructor.

like image 139
T.C. Avatar answered Apr 21 '26 21:04

T.C.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!