2015-03-08 15 views
6

już wiem, że można włączyć (lub nie) metodę klasy Korzystanie std::enable_ifumożliwić państwom klasę w zależności od szablonu

dla exemple:

template<size_t D, size_t E> 
class Field 
{ 
    ... 

    size_t offset(const std::array<float,D>& p) const 
    { 
    ... 
    } 

    template<typename TT = size_t> 
    typename std::enable_if<D!=E, TT>::type 
    offset(const std::array<float,E>& p) const 
    { 
    return offset(_projection(p)); 
    } 

    ... 
}; 

To nie pomaga będąc w stanie funkcjonować, że są nieważne zadzwonić w konkretnym przypadku, a także usuwanie błędów przeciążania ... co dla mnie jest bardzo miłe!

Chciałbym pójść dalej i sprawić, że niektórzy członkowie mojej klasy będą obecni tylko wtedy, gdy będą potrzebni. W ten sposób będę się błąd, gdy próbuję użyć sprzeciwił który byłby inaczej nie zostało wszczęte

Próbowałem zrobić

template<size_t D, size_t E> 
class Field 
{ 
    ... 

    template<typename TT = projectionFunc> 
    typename std::enable_if<D!=E, TT>::type _projection; 
} 

ale kompilator mówi mi:

erreur: data member ‘_projection’ cannot be a member template 

Czy czy istnieje jakiś sposób osiągnięcia tego, czego chcę?

+3

Możesz chcieć zmienić nazwę z 'offsetof', aby ktoś nie zawarł przed nagłówkiem i nie zaangażował się w to makro. – chris

+0

To jest planowane, szukam po prostu innej fajnej nazwy. – Amxx

+0

Ta konkretna SFINAE też jest trochę ... icky. W przypadku 'D == E' kończysz na' typename std :: enable_if :: type'. Specjalizującą się cechą standardowej biblioteki jest UB, więc można argumentować, że hipotetyczna implementacja może odwoływać się do reguły "brak ważnej specjalizacji można wygenerować" i nazwać to źle sformułowanym. –

Odpowiedz

5

Trzymaj członków danych w oddzielnej klasie, którą możesz następnie wyspecjalizować w razie potrzeby.

template<size_t D, size_t E> 
class Field { 
    template<size_t, size_t> struct Field_Members { 
     int _projection; 
    }; 
    template<size_t V> struct Field_Members<V, V> { }; 
    Field_Members<D, E> m; 
}; 

a następnie użyć m._projection itp

Field_Members nie musi być zagnieżdżona klasa szablon; w razie potrzeby można go przenieść na zewnątrz. Możliwe jest również odziedziczenie z niego Field, ale wówczas będzie to zależna baza i trzeba będzie napisać this->_projection, aby nie zapisywać zbyt wiele pisania.

4

AFAIK, nie jest to możliwe z prostym SFINAE wewnątrz szablonu klasy. Oczywiście można uzależnić typ elementu od stanu kompilacji, tj. Poprzez std::conditional, ale nie można całkowicie wyeliminować członka.

Co można zrobić, jest oczywiście użyć innego szablonu klasy, takie jak

template<bool Condition, typename T> struct Has { T value; }; 
template<typename T> struct Has<false,T> {}; 

i zadeklarować członka (lub bazę) tego typu, a dostęp do obiektu poprzez Has<>::value:

typename<Condition> 
class foo 
{ 
    Has<Condition, double> x; // use x.value (only if Condition==true) 
};