2016-04-09 8 views
0

Bitte beachten Sie:Der Template-Parameter meiner partiellen Vorlage Spezialisierung ist die folgende Code-Schnipsel nicht ableitbar

template<class E> 
class vector_expression {}; 

template<class Tuple> 
class vector 
    : public vector_expression<vector<Tuple>> 
{ 
public: 
    using value_type = typename Tuple::value_type; 
}; 

template<typename T> 
using dynamic_vector = vector<std::vector<T>>; 

namespace detail 
{ 
    template<class E> 
    constexpr bool is_vector_expression_v = std::is_base_of_v<vector_expression<std::decay_t<E>>, std::decay_t<E>>; 

    template<class E> 
    struct value_type { using type = std::decay_t<E>; }; 
    template<class E> 
    struct value_type<vector_expression<std::decay_t<E>>> { using type = typename std::decay_t<E>::value_type; }; 
    template<class E> 
    using value_type_t = typename value_type<E>::type; 
} 


int main() 
{ 
    static_assert(std::is_same<detail::value_type_t<dynamic_vector<double>>, double>::value, "not the same"); 
    return 0; 
} 

ich value_type_t<E> wollen die value_type in E angegeben sein, wenn E ein vector_expression ist. Der obige Code funktioniert nicht, da der Template-Parameter E in der Teilspezialisierung value_type nicht ableitbar ist. Wie kann ich den Code arbeiten lassen?

DEMO

+0

Wie [hier] (http://coliru.stacked-crooked.com/a/35a7e10935ac63a0)? –

Antwort

2

std::decay_t<E> ist nicht ableitbar, wie es in der Tat std::decay<E>::type ist (und in der Tat mehrere E zu gleichen Typ in Ihrem speziellen Fall führen kann).

Ein zweites Update benötigt wird Ihre static_assert weitergeben müssen:

Als dynamic_vector<double> ist nicht vector_expression aber erben von ihm, Ihre Spezialisierung nicht übereinstimmt. Sie können SFINAE verwenden, das zu beheben:

template<class E, typename Enabler = void> 
struct value_type { using type = std::decay_t<E>; }; 

template<class E> 
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> { 
    using type = typename std::decay_t<typename E::type>::value_type; 
}; 

Demo

1

Das erste Problem ist, dass Ihre Teil-Spezialisierung ist nicht ableitbar. Das ist ein einfacher zu beheben, können Sie einfach die std::decay_t fallen:

template<class E> 
struct value_type<vector_expression<E>> { using type = typename E::value_type; }; 

aber jetzt haben Sie das größere Problem, dass dies nicht tun, was Sie wollen, es zu tun. dynamic_vector<double> ist kein vector_expression<E> für irgendeinen E. Es erbt von vector_expression<vector<std::vector<T>>>, aber das wird für die Zwecke dieses Spiels nicht helfen. Also wird der obige Fix kompiliert, aber Sie würden immer noch die primäre Vorlage zuordnen - geben Sie die falsche value_type.

Was Sie wahrscheinlich wollen, ist auf das Vorhandensein von value_type als Typdef zu spezialisieren. Das ist:

template <class... > using void_t = void; 
template <class T> struct tag_t { using type = T; }; // courtesy of Yakk 

template<class E, class=void> 
struct value_type : tag_t<std::decay_t<E>> { }; 

template<class E> 
struct value_type<E, void_t<typename std::decay_t<E>::value_type>> 
: tag_t<typename std::decay_t<E>::value_type> { }; 

Und jetzt Ihre static_assert geht.