【问题标题】:Overriding a virtual method in a base class with conditional type traits in derived template class在派生模板类中使用条件类型特征覆盖基类中的虚拟方法
【发布时间】:2017-09-11 20:35:41
【问题描述】:

谁能解释一下为什么下面的代码会在 Visual Studio 2015 C++ 中给出错误“error C2259: 'PropertyValue': cannot instantiate abstract class”?

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

非常感谢,

约翰

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

【问题讨论】:

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


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢先生,这是完美的答案,让我很开心。
【解决方案2】:

问题是

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    • 2020-11-05
    • 1970-01-01
    • 2018-06-06
    • 2016-03-17
    • 2021-06-15
    相关资源
    最近更新 更多