0

The following code compiles successfully with gcc but fails to compile in Visual Studio 2013:

#include <memory>
#include <iostream>

using namespace std;

template <typename T>
class MyClass {
public:
    MyClass(T* ptr) : m_ptr(ptr) {}

    // All of the errors are caused by this conversion operator:
    // =========================================================
    template <typename U>
    operator typename std::shared_ptr<U>() const & {
        return m_ptr;
    }
    //==========================================================

private:
    shared_ptr<T> m_ptr;
};

int main(int argc, char* argv[]) {
    MyClass<int> c(new int(42));

    shared_ptr<int> ptr = c;
    cout << *ptr << endl;
}

I am fairly certain this is a bug in the VS2013 compiler because it does compile in newer versions of Visual Studio, but the problem is where I work, we are stuck using VS2013. Getting them to switch compilers is out of the question. (We have to use the same compiler that the vendor who supplies our software uses and they use VS2013.)

The errors are listed below:

Error   1   error C2143: syntax error : missing ';' before '&'  
Error   2   error C2238: unexpected token(s) preceding ';'  
Error   3   error C2988: unrecognizable template declaration/definition 
Error   4   error C2059: syntax error : '<end Parse>'   
Error   5   error C2334: unexpected token(s) preceding ':'; skipping apparent 
Error   6   error C1004: unexpected end-of-file found   

My question, is even with the limitations of VS2013, is there any workaround possible to get this code to compile and run successfully?

tjwrona1992
  • 8,614
  • 8
  • 35
  • 98
  • Recommend marking up the code to point where the errors are. – user4581301 Jul 31 '18 at 21:41
  • @user4581301, I surrounded the section of code that is causing errors with a comment. The errors are very non-descriptive in general and don't help much. – tjwrona1992 Jul 31 '18 at 21:44
  • I think there is a dupe for this, trying to find it. The code should compile with `operator std::shared_ptr() const &` since the `typename` is not needed. – NathanOliver Jul 31 '18 at 21:44
  • Works for me. The location of most of them was pretty easy to work out since there's only one `&` in the code, but every little bit helps. – user4581301 Jul 31 '18 at 21:45
  • @NathanOliver, I just tried that and it still fails to compile. :( There are similar questions about how this doesn't work in Visual Studio 2013, but the answer is always that it is a bug in the compiler and no one has explicitly asked if there is a workaround to make it work with this compiler version. – tjwrona1992 Jul 31 '18 at 21:45
  • @tjwrona1992 Looks like [this](https://stackoverflow.com/questions/28963856/visual-studio-2013-c-problems-with-reference-qualifiers) is it. There is no workaround except to not use the reference qualifier. – NathanOliver Jul 31 '18 at 21:49
  • Whether or not this is valid C++, trying to return a const reference like that, when a conversion temporary is possible, only invites a world of hurt and undefined behavior, at the slightest provocation. The short version: don't do it. – Sam Varshavchik Jul 31 '18 at 21:50
  • @NathanOliver, Ahh okay, that solves this case, but what about for move semantics? I need to implement that as well – tjwrona1992 Jul 31 '18 at 21:50
  • @SamVarshavchik, can you elaborate? I don't fully understand what you mean. The code that is doing this has to be used as a drop in replacement for another smart pointer class so the implicit type conversion is necessary or it would involve code changes all over our system to make it work with a new type. – tjwrona1992 Jul 31 '18 at 21:52
  • @tjwrona1992 See [this](https://msdn.microsoft.com/en-us/library/hh567368.aspx#corelanguagetable) for everything that is supported. – NathanOliver Jul 31 '18 at 21:52
  • @SamVarshavchik Where is the OP returning a reference? – NathanOliver Jul 31 '18 at 21:53
  • In the conversion operator. – Sam Varshavchik Jul 31 '18 at 21:54
  • @SamVarshavchik The return type is `std::shared_ptr`. the `const &` is the const and reference qualifications of the function. – NathanOliver Jul 31 '18 at 21:54
  • 1
    The right hand side of the `()` is not part of the return type. – NathanOliver Jul 31 '18 at 21:55
  • @NathanOliver, Does this mean there would be no way to implement move semantics in Visual Studio 2013? i.e. `operator typename std::shared_ptr() const && { ... }` – tjwrona1992 Jul 31 '18 at 21:56
  • @tjwrona1992 That is not what implements move semantics. have a `&` at the end of a function means only a lvalue can call that function. Having a `&&` means only a rvalue can call that function. MSVS 2013 supports rvalue references and move semantics. `operator typename std::shared_ptr() const` will do what you want. – NathanOliver Jul 31 '18 at 21:58
  • @NathanOliver, okay thank you. One last question. Sorry to ask so many things. If removing the & will do everything I want then what is the purpose of defining conversion operators with & or && when leaving off & does everything? – tjwrona1992 Jul 31 '18 at 22:16
  • @tjwrona1992 The purpose would be if you only want an lvalue or rvalue to be convert-able. I'm not sure why you would want that but you can have it. – NathanOliver Aug 01 '18 at 12:37
  • @NathanOliver, what about the situation where you want to do this? `std::shared_ptr ptr = std::move(myobject);` The move would not give up ownership of the object unless you implemented a different conversion for rvalue objects that explicitly gives up ownership. – tjwrona1992 Aug 01 '18 at 13:35

0 Answers0