3

I am trying to implement a clone method (deep copy) with covariance in the context of a diamond inheritance with a common base (this is why I need the virtual keyword in C1 and C2 classes declaration). It works pretty well if I have only typed template arguments but it does not compile anymore if I add non-typed template.

To be more specific, the code compile with GCC, Clang and ICC but not with MSVC and I would like to keep the compatibility with this compiler...

Here is the code:

class C0
{
public:
    C0() = default;
    virtual ~C0() = default;
    virtual C0* clone() const { return new C0(); }
    virtual void foo()  {  std::cout << "I'm C0!" << std::endl;  }
};

template <typename T = int>
class C1 : virtual public C0
{
public:
    C1() = default;
    virtual ~C1() = default;
    // here I would like to return a C1<T>* but it seems that there is an unresolved bug with diamond inheritance and covariance in MSVC
    virtual C0* clone() const { return new C1(); }
    virtual void foo() { std::cout << "I'm C1!" << std::endl; }
};

template <typename T = int>
class C2 : virtual public C0
{
public:
    C2() = default;
    virtual ~C2() = default;
    // here I would like to return a C2<T>* but it seems that there is an unresolved bug with diamond inheritance and covariance in MSVC
    virtual C0* clone() const { return new C2(); }
    virtual void foo() { std::cout << "I'm C2!" << std::endl; }
};

template <typename T = int>
class C3 : public C1<T>, C2<T>
{
public:
    C3() : C0(), C1<T>(), C2<T>() {}
    virtual ~C3() = default;
    // here I would like to return a C3<T>* but there is an unresolved bug with diamond inheritance and covariance in MSVC
    virtual C0* clone() const { return new C3(); }
    virtual void foo() { std::cout << "I'm C3!" << std::endl; }
};

template <typename T>
using proto = T (*)();

template <typename T>
T func() { return (T)10; }

// P is a non-typed template
template <typename T = int, proto<T> P = func>
class C4 : public C3<T>
{
public:
    C4() : C0(), C3<T>() {}
    virtual ~C4() = default;
    // here is my bug, I can't force MSVC to compile this function (even if I replace 'C4<T,P>*' 'by C3<T>*', note that it compiles with 'C0*' type')
    virtual C4<T,P>* clone() const { return new C4(); }
    virtual void foo() {  std::cout << "I'm C4 : " << P() << "!" << std::endl; }
};

// This code works (without the non-typed template param)
/*
template <typename T = int>
class C4 : public C3<T>
{
public:
    C4() : C0(), C3<T>() {}
    virtual ~C4() = default;
    virtual C4<T>* clone() const { return new C4(); }
    virtual void foo() {  std::cout << "I'm C4!" << std::endl; }
};
*/

int main(int argc, char** argv)
{
    C0* ca = new C4<>();
    C0* cb = ca->clone();

    cb->foo();

    delete ca;
    delete cb;

    return 0;
}

If someone is interested to test this code, I made a repository on GitHub here: https://github.com/kouchy/clone_bug_msvc.

I tested the code on Visual Studio 2017 (MSVC 14.1) and 2019 (MSVC 14.2) and it fails on both compiler, the returned error is:

>------ Build started: Project: CMakeLists, Configuration: Debug ------
  [1/2] C:\PROGRA~2\MICROS~1\2017\COMMUN~1\VC\Tools\MSVC\1412~1.258\bin\HostX86\x86\cl.exe  /nologo /TP   /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 /showIncludes /FoCMakeFiles\clone.dir\src\main.cpp.obj /FdCMakeFiles\clone.dir\ /FS -c C:\Users\ci\source\repos\clone_bug_msvc\src\main.cpp
  FAILED: CMakeFiles/clone.dir/src/main.cpp.obj 
  C:\PROGRA~2\MICROS~1\2017\COMMUN~1\VC\Tools\MSVC\1412~1.258\bin\HostX86\x86\cl.exe  /nologo /TP   /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 /showIncludes /FoCMakeFiles\clone.dir\src\main.cpp.obj /FdCMakeFiles\clone.dir\ /FS -c C:\Users\ci\source\repos\clone_bug_msvc\src\main.cpp
C:\Users\ci\source\repos\clone_bug_msvc\src\main.cpp(60): error C2062: type 'int' unexpected
  ninja: build stopped: subcommand failed.

Any help will be greatly appreciated :-)!

Kouchy
  • 31
  • 1
  • 1
    You should use `override` instead of `virtual` when overriding methods. – Axalo Nov 20 '19 at 20:40
  • I tried to put override instead of virtual keyword and there is still the same compilation error. – Kouchy Nov 20 '19 at 21:04
  • Looks legit. Maybe reporting it as a bug would be more effective than looking for a solution here: https://learn.microsoft.com/en-us/cpp/overview/how-to-report-a-problem-with-the-visual-cpp-toolset?view=vs-2019 – parktomatomi Nov 26 '19 at 02:16

0 Answers0