2017-09-11 81 views
0

任何人都可以解釋爲什麼下面的代碼在Visual Studio 2015 C++中出現錯誤「錯誤C2259:'PropertyValue':無法實例化抽象類」?在派生模板類中用條件類型特徵覆蓋基類中的虛方法

編譯器無法識別派生類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; 
} 

[編輯]這不是一個重複的問題,因爲條件性狀方面的。

+2

一個好的技巧是始終聲明函數'override'您打算要重寫;那麼如果你實際上沒有覆蓋任何東西,你將會遇到編譯器錯誤 – Justin

+0

當你[添加'override'關鍵字](https://godbolt.org/g/ue7EGk)時,編譯器很好的解釋了爲什麼這樣做不工作:「成員模板...可能沒有virt-specifiers」。基本上,你不能混用虛函數和模板 – Justin

+2

[C++類的成員函數模板可以虛擬嗎?](https://stackoverflow.com/questions/2354210/can-ac-class-member-function- template-be-virtual) – Justin

回答

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

謝謝先生,這是完美的答案,並讓我的一天。 – user7283981

相關問題