2016-07-28 22 views
6

Czy można wyłączyć funkcje pojedynczego elementu klasy szablonu za pomocą SFINAE i std::enable_if?Użycie SFINAE w celu wyłączenia funkcji elementu szablonu klasy


Obecnie mam kodu podobnego do tego:

#include <type_traits> 
#include <iostream> 
#include <cassert> 
#include <string> 

class Base { 
public: 
    virtual int f() { return 0; } 
}; 

template<typename T> 
class Derived : public Base { 
private: 
    T getValue_() { return T(); } 

public: 
    int f() override { 
     assert((std::is_same<T, int>::value)); 
     T val = getValue_(); 
     //return val; --> not possible if T not convertible to int 
     return *reinterpret_cast<int*>(&val); 
    } 
}; 


template<typename T> 
class MoreDerived : public Derived<T> { 
public: 
    int f() override { return 2; } 
}; 


int main() { 
    Derived<int> i; 
    MoreDerived<std::string> f; 
    std::cout << f.f() << " " << i.f() << std::endl; 
} 

Idealnie Derived<T>::f() powinna być wyłączona, jeśli T != int. Ponieważ f jest wirtualny, generowany jest Derived<T>::f() dla dowolnego wystąpienia Derived, nawet jeśli nigdy nie jest wywoływany. Ale kod jest używany tak, że Derived<T> (z T != int) nigdy nie zostanie utworzony tylko jako klasa podstawowa z MoreDerived<T>.

Tak więc włamanie w Derived<T>::f() jest konieczne, aby program się skompilował; linia reinterpret_cast nigdy nie zostanie wykonana.

+2

Co o specjalizacji szablonu do int? – wasthishelpful

Odpowiedz

6

Można po prostu specjalizują f dla int:

template<typename T> 
class Derived : public Base { 
private: 
    T getValue_() { return T(); } 

public: 
    int f() override { 
     return Base::f(); 
    } 
}; 

template <> 
int Derived<int>::f() { 
    return getValue_(); 
} 
5

Nie można wykluczyć funkcji członka za pomocą SFINAE. Można to zrobić ze specjalizacją funkcji klasy Derived klasy f dla przekształcalnych T s na int, ale to może prowadzić do niepotrzebnego powielania kodu. W C++ 17 jednak można rozwiązać ten problem przy użyciu if constexpr:

template<typename T> class Derived : public Base { 
    T getValue_() { return T(); } 
public: 
    int f() override { 
    if constexpr(std::is_convertible<T, int>::value) return getValue_(); 
    return Base::f(); 
    } 
}; 

Live Demo

Powiązane problemy