在派生模板类中使用条件类型特征覆盖基类中的虚方法

时间:2017-09-11 20:35:41

标签: c++ c++11 templates sfinae typetraits

任何人都可以解释为什么下面的代码会给出错误"错误C2259:' PropertyValue':无法实例化抽象类"在Visual Studio 2015 C ++中?

编译器是否无法识别派生类ConvertToDevice()中的条件指定函数PropertyValue是否具有相同的签名?

非常感谢,

约翰

#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]由于条件特征方面,这不是一个重复的问题。

2 个答案:

答案 0 :(得分:2)

首先,您声明要尝试覆盖的函数作为模板。你不能拥有模板虚拟功能。就这么简单。

对于解决方案,您似乎只是为了能够在两个实现之间切换而使这些模板。一个简单的解决方案是实现一个覆盖的单个函数,然后在其中调用模板函数:

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;
    }
};

答案 1 :(得分:1)

问题在于

template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
    return 1;
}

模板方法,它与基类中的纯虚方法不匹配(并且不会覆盖)。

与其他启用SFINAE的功能相同。

所以PropertyValue仍然是纯虚拟类,无法实例化。

可能的解决方案是创建一个中间基类,如下面的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; }
 };