Reputation: 149
Can anyone explain why the code below gives the error "error C2259: 'PropertyValue': cannot instantiate abstract class" in Visual Studio 2015 C++?
Is the compiler not able to identify that the conditionally specified function ConvertToDevice()
in the derived class PropertyValue
has the same signature?
Many thanks,
John
#include <type_traits>
#include <typeinfo>
class BasePropertyValue
{
public:
virtual int ConvertToDevice(void** ptrdObject) = 0;
};
template<typename T> class PropertyValue : public BasePropertyValue
{
public:
T value;
PropertyValue(T val)
{
value = val;
}
template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
return 1;
}
template<class Q = T>
typename std::enable_if<std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
return 2;
}
};
void main()
{
PropertyValue<double>* prop1 = new PropertyValue<double>(20);
prop1->ConvertToDevice(nullptr);
double x = 20;
PropertyValue<double*>* prop2 = new PropertyValue<double*>(&x);
prop2->ConvertToDevice(nullptr);
return;
}
[edit] This is not a duplicate question because of the conditional traits aspect.
Upvotes: 0
Views: 1116
Reputation: 41800
First, you declare the function you're trying to override as templates. You cannot have template virtual function. It's as simple as that.
For for the solution, you seem to have made those templates just to be able to switch between two implementation. A simple solution would be to implement a single function that overrides, and then call a template function in it:
template<typename T>
struct PropertyValue : BasePropertyValue {
T value;
// simpler constructor
PropertyValue(T val) : value{std::move(val)} {}
// the override keyword is important
int ConvertToDevice(void** ptrdObject) override
{
return ConvertToDeviceImpl(ptrdobject);
}
private:
template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type
ConvertToDeviceImpl(void** ptrdObject)
{
return 1;
}
template<class Q = T>
typename std::enable_if<std::is_pointer<Q>::value, int>::type
ConvertToDeviceImpl(void** ptrdObject)
{
return 2;
}
};
Upvotes: 2
Reputation: 66230
The problem is that
template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
return 1;
}
is a template method that doesn't match (and not override) the pure virtual method in the base class.
Same problem with the other SFINAE enabled function.
So PropertyValue
remain a pure virtual class and can't be instantiated.
A possible solution is to create a intermediate base class, as the following midClass
class BasePropertyValue
{ public: virtual int ConvertToDevice (void ** ptrdObject) = 0; };
template <typename T, bool = std::is_pointer<T>::value>
class midClass;
template <typename T>
class midClass<T, false> : public BasePropertyValue
{ public: int ConvertToDevice (void ** ptrdObject) override { return 1; } };
template <typename T>
class midClass<T, true> : public BasePropertyValue
{ public: int ConvertToDevice (void ** ptrdObject) override { return 2; } };
template <typename T>
class PropertyValue : public midClass<T>
{
public:
T value;
PropertyValue (T val)
{ value = val; }
};
Upvotes: 1