3

This looks like a compiler bug, but the case is so simple I am a bit skeptical, so I am looking for a confirmation. Reproducible with both VS2010 and VS2012. The below example does not compile. This error is given:

Error 1 error C2440: 'type cast' : cannot convert from 'ConvertibleToAny' to 'OtherType<_Ty>' test.cpp 40

If you move the position of the move constructor OtherType(ThisType &&) above the constructor OtherType( int ), it suddenly compiles.

#include "stdafx.h"
#include <string>

using namespace std;

template<class _Ty>
struct OtherType
{
  typedef OtherType<_Ty>  ThisType;

  OtherType()
  { 
  }

  OtherType( int )
  { 
  }

  // The move constructor
  OtherType(ThisType && )
  {
  }
};

struct ConvertibleToAny
{    
  template <class AnyType>
  operator AnyType()
  {
    return AnyType();
  }
};

int _tmain(int argc, _TCHAR* argv[])
{

  (OtherType<wstring>) ConvertibleToAny();

    return 0;
}

Is this a bug or is this expected behavior? If it's expected, please quote the relevant paragraph from the C++11 specification. I already posted this as a bug at Microsoft Connect, click here to open it.

EddieBytes
  • 1,333
  • 9
  • 20
  • *"If you move the position of the move constructor above the [other] constructor"* - If that is really the solution, this can never be expected behaviour. – Christian Rau Sep 11 '12 at 07:49
  • yes, that's what I am thinking too, but the case is so simple I find it a bit hard to believe it simply slipped, and is a bug. – EddieBytes Sep 11 '12 at 07:50
  • @EddieBytes Bug in MSVC is, that moving of move c-tor fix problem. Your code is incorrect by C++ standard. – ForEveR Sep 11 '12 at 08:00
  • @ForEveR I am sorry, I am not sure I understand. Could you please elaborate? – EddieBytes Sep 11 '12 at 08:02
  • @ForEveR why is my code incorrect? – EddieBytes Sep 11 '12 at 08:11
  • 1
    Note: The position/order of constructors, etc. does not matter. The behavior you are seeing is a result of the [MSVC compiler not compiling templates correctly](http://stackoverflow.com/questions/6273176/what-exactly-is-broken-with-microsoft-visual-cs-two-phase-template-instanti) . It helps to use a better compiler such as gcc or clang for these types of issues. – Jesse Good Sep 11 '12 at 21:54
  • @JesseGood very good comment, that explains things. – EddieBytes Sep 12 '12 at 06:49

1 Answers1

6

Your expression

(OtherType<wstring>) ConvertibleToAny()

is a unary explicit cast (5.4) from a temporary of user-defined type to a user-defined type, interpreted per 5.4:4 as a static_cast:

static_cast<OtherType<wstring>>(ConvertibleToAny())

which per 5.2.9:4 has the validity of initializing a temporary variable t:

OtherType<wstring> t(ConvertibleToAny())

This is direct-initialization (8.5:15) and as such (8.5:16) all the one-argument constructors of OtherType participate in overload resolution per the rules in 13.3.1.3.

Following 13.3:2, both the int and move constructors are available and are viable per 13.3.2, so we have two possible implicit conversion sequences (13.3.3.1) for the single argument:

ConvertibleToAny [temporary] -> int
ConvertibleToAny [temporary] -> OtherType<wstring> &&

Following 13.3.3.1.2 there is no ordering between these sequences, so there is no best viable function, overload resolution fails (13.3:3), and the program is ill-formed.


If the conversion function (12.3.2) is made explicit (12.3.2:2) then it is only considered for direct-initialization. Although implicit conversion sequences (13.3.3.1) are implicit conversions (4:3) and so involve copy-initialization, the intent of the standard in the example to 12.3.2:2 is clearly that explicit conversion functions should be considered in this case; as such, it appears again that overload resolution should fail.

ecatmur
  • 152,476
  • 27
  • 293
  • 366