2016-04-09 9 views
0

推論ではありません次のコードスニペットを考えてみてください:テンプレートパラメータは

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

私はvalue_type_t<E>Evector_expressionである時はいつでもEで指定value_typeになりたいです。上記のコードが機能していないため、テンプレートパラメータEは、部分的な特殊化value_typeでは推測できません。コードを動作させるにはどうしたらいいですか?

DEMO

+0

[こちら](http://coliru.stacked-crooked.com/a/35a7e10935ac63a0)のように? –

答えて

2

std::decay_t<E>それは実際std::decay<E>::typeであるとして(実際、いくつかのEがあなたの特定のケースでは、同じタイプにつながることができます)推論ではありません。

秒修正はあなたのstatic_assertに合格するために必要とされる:dynamic_vector<double>として

vector_expressionではなく、それを継承し、自分の専門分野は一致していません。あなたはそれを修正するためにSFINAEを使用することがあります。

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

第一の問題は、あなたの部分的な特殊化は、非推論であるということです。それはあなただけstd::decay_tをドロップすることができ、簡単に修正です:

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

はしかし、今は、これはあなたがそれをやりたいしないという点で大きな問題を抱えています。 dynamic_vector<double>Eの場合はvector_expression<E>ではありません。 vector_expression<vector<std::vector<T>>>から継承していますが、この試合の目的には役立ちません。したがって、上記の修正はコンパイルされますが、あなたはまだプライマリテンプレートと一致します - 間違ってvalue_typeを与えます。

value_typeがtypedefとして存在することを専門とすることをお勧めします。つまり、

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> { }; 

あなたのstatic_assertが合格しました。

関連する問題