2017-01-19 7 views
0

私は、特定の条件が真であるかどうかを返す、型特性として機能するクラスを持っています。クラスを特定の機能をサポートするものとしてマークすることを意図しています。テンプレートの内部型のクラスを特殊化する方法は?

template <typename T> struct Check : std::false_type { }; 

私は内部クラスを含むテンプレートクラスを持っている:

template <unsigned N> 
struct Kitty 
{ 
    struct Purr; 
}; 

は私がCheckと表記機能をサポートするよう内部クラスPurrをマークしたいです。つまり、Check<Kitty<123>::Purr>::valuetrueであるようにしたいと思います。私は次のことをやってみましたが、私はエラーを取得:

template <unsigned X> 
struct Check<typename Kitty<X>::Purr> : std::true_type { }; 

error: template parameters not deducible in partial specialization:

それは、これを達成することは可能ですか、それはあなたが内側のテンプレートクラスのメンバーに特化することはできませんC++の制限ですが?

+0

いいえ、エラーは問題の内容を明確に示しています。それはあなたの提案ではなく、限界です。 'struct check :: Purr>:true_type {};'のようなものは問題ありません。 – DeiDei

+0

[テンプレートの引数の控除がここで機能しないのはなぜですか?](http://stackoverflow.com/questions/1268504/why-is-the-template-argument-deduction-not-working-here) – LogicStuff

+0

明らかですそれはあなたがカバーするキティ::プルのすべての専門化を意味します。しかし、 'Kitty'の特殊化に' Purr'( 'template <> struct Kitty <0> {};')がないとどうなるか考えてみてください。言語は、あなたが単にそれを行うことはできないと言ってこれを解決します。この場合、単にその専門化を無視するか、それともすべての専門化がそれに準拠しなければならないと言われてもいいでしょう。あなたができることは基本クラス 'struct KittyBase {struct Purr;}を作ることです。 };そして 'キティ'にそれを継承させる。 'N 'にアクセスするために' Purr'が必要ですか? 'Purr'をベースにテンプレートにします。 – chris

答えて

1

私のコメントで概説したように、私がKittyBaseと呼ぶことにしますこれは、基本クラスを使用して、この推論に関連することが可能です。基本クラスを使用することは、実際にはテンプレートの共通点です。新しいインスタンス化ごとに不要なコードが重複することを避けるためです。同じテクニックを使用してPurrを取得し、Nを推測する必要はありません。

ただし、Purrを基本クラスに入れると、そのアクセスはNになりません。必要であれば、あなたもKittyBase::Purrをプライベートにすると特性へのアクセスを許可するtemplate<typename T> friend struct Check;を使用することができますLive example

#include <type_traits> 

template <typename T> struct Check : std::false_type { }; 

struct KittyBase 
{  
    template<unsigned N> // Template if Purr needs N. 
    struct Purr; 

protected: 
    ~KittyBase() = default; // Protects against invalid polymorphism. 
}; 

template <unsigned N> 
struct Kitty : private KittyBase 
{ 
    using Purr = KittyBase::Purr<N>; // Convenience if Purr needs N. 
    Purr* meow; 
}; 

template <unsigned X> 
struct Check<typename KittyBase::Purr<X>> : std::true_type { }; 

static_assert(not Check<int>{}); 
static_assert(Check<Kitty<123>::Purr>{}); 
static_assert(Check<Kitty<0>::Purr>{}); 

int main() {} 

:幸いなことに、でもPurr自身のテンプレートを作成するには、これはまだ非推測コンテキストすることができます。残念ながら、私はあなたがその特質の特定の専門化に限定できるかどうかはわかりません。

1

This answerは、タイプがSFINAEを使用して存在するかどうかを調べる興味深いアプローチを持っています。

T :: Purr型が存在するかどうかを調べるために、問題のある特殊化を行わずに型形質を書き込むことができます。

#include <type_traits> 

template <unsigned T> 
struct Kitty 
{ 
    struct Purr{}; 
}; 

// A specialization without Purr, to test 
template <> 
struct Kitty<5>{ }; 

// has_purr is taken and adapted from https://stackoverflow.com/a/10722840/7359094 
template<typename T> 
struct has_purr 
{ 
    template <typename A> 
    static std::true_type has_dtor(decltype(std::declval<typename A::Purr>().~Purr())*); 

    template<typename A> 
    static std::false_type has_dtor(...); 

    typedef decltype(has_dtor<T>(0)) type; 

    static constexpr bool value = type::value; 
}; 

// Check if a type is an instance of Kitty<T> 
template<typename T> 
struct is_kitty : std::false_type {}; 
template<unsigned T> 
struct is_kitty<Kitty<T>> : std::true_type {}; 

template <typename T> 
struct Check : std::bool_constant< is_kitty<T>::value && has_purr<T>::value> {}; 

static_assert(Check<int>::value == false, "int doesn't have purr"); 
static_assert(Check<Kitty<0>>::value == true, "Kitty<0> has purr"); 
static_assert(Check<Kitty<5>>::value == false, "Kitty<5> doesn't has purr"); 
関連する問題