2017-09-11 20 views
0

누군가 아래의 코드에서 오류 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; 
} 

[편집]이 때문에 조건부 특성 측면의 중복 질문이 아니다.

+2

좋은 팁은 항상 기능은'당신이 무시 될 예정 것을 override' 선언하는 것입니다; 실제로 아무 것도 무시하지 않으면 컴파일러 오류가 발생합니다. – Justin

+0

[override 키워드 추가] (https://godbolt.org/g/ue7EGk) 컴파일러는 왜 이것이 작동하지 않는지 잘 설명합니다 '일하지 마라 : "회원 템플릿 ... virt-specifier가 없을 수도 있습니다." 기본적으로 가상 함수와 템플릿을 함께 사용할 수 없습니다. – 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