Reputation: 489
I have a code snippet which used to work properly when conformance mode settings were set to off. When I set the conformance mode to (/permissive-). I am facing error in part of the code where template template parameter is involved.
My code is as follows:
template <typename T> using IsNotLValue = std::enable_if_t<!std::is_lvalue_reference_v<T>>;
// Base Class Template
template <typename T> class MyClassBase
{
protected:
template <typename T_ = T, typename = IsNotLValue<T_>>
explicit MyClassBase(T &&ptr) : ptr_(std::move(ptr))
{
std::cout << "MyClassBase ::IsNotLValue" << std::endl;
}
T ptr_ = nullptr;
};
// Derived Class Template
template<typename T> class MyClass : public MyClassBase<T>
{
public:
template <typename T_ = T, typename = IsNotLValue<T_>>
MyClass(T &&ptr) : MyClassBase<T>(std::move(ptr))
{
std::cout << "MyClass :: IsNotLValue" << std::endl;
}
};
// Base Class
class Base
{
public:
int x = 0;
Base() : x(10) {}
};
// Derived Class
class Derived : public Base
{
public:
Derived() :Base(), y(20) {}
int y = 0;
};
// Function returning MyClass Object to pointer to Base Class Type
MyClass<Base*> ptrToBase()
{
return new Derived(); // Line 1 : OK
}
// Function returning uniqueptr to MyClass Object to pointer to Base Class Type
MyClass<std::unique_ptr<Base>> uniquePtrToBase()
{
return std::make_unique<Derived>(); // Line 2 :compilation error here
}
int main()
{
auto pUB = uniquePtrToBase();
auto pB = ptrToBase();
return 0;
}
Line 2 is giving compilation error when conformance mode is set to ON. It is getting fixed, If I add another constructor as below:
template <typename D, typename = IsNotLValue<D>>
MyClass(D &&ptr) : MyClassBase<T>(std::move(ptr))
{
std::cout << "MyClass for uniqueptr" << std::endl;
}
However, I want to enable this function only if template parameter for D is derived from template parameter of T or D is derived from T, so I modified the condition to :
template <typename D, typename T> using IsConvertibleToBase =
std::enable_if_t<std::is_convertible_v<D*, T*>>;
template <typename D, typename = IsConvertibleToBase<D, T>>
MyClass(D &&ptr) : MyClassBase<T>(std::move(ptr))
{
std::cout << "MyClass :: IsConvertibleToBase" << std::endl;
}
This code is giving compilation error because, here D is std::unique_ptr<Derived>
and T is std::unique_ptr<Base>
. Hence, is_convertible is failing.
How can I ensure that this ctor is enabled only for inherited classes? And Why this error is occurring with conformance mode on, if its the ZC conformance mode, then which one? I tried overriding twoPhase, that didnt work?
Upvotes: 0
Views: 402
Reputation: 327
template <typename D, typename T>
using IsConvertibleToBase = std::enable_if_t<std::is_convertible_v<D*, T*>>;
With above definition, D*
and T*
will be an error when IsConvertibleToBase
is used with unique_ptr
.
One solution is to use pointer_traits
which will work for any pointer-like type:
template <typename D, typename T>
using IsConvertibleToBase = std::enable_if_t<
std::is_convertible_v<typename std::pointer_traits<D>::pointer,
typename std::pointer_traits<T>::pointer>>;
Upvotes: 1