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 :-)!