2017-06-18 12 views
5

unique_ptrを持つほとんどの専門の私は、部分的に特化したテンプレートを作成しようとしています、とstd::unique_ptrC++テンプレート部分的な特殊 - <t>

template <typename T, typename = void> 
struct Foo; 

// A 
template <typename T> 
struct Foo<std::unique_ptr<T>, typename std::enable_if<std::is_class<T>::value>::type> {...}; 

// B 
template <typename T> 
struct Foo<T, typename std::enable_if<std::is_class<T>::value>::type> {...}; 

void fn() { 
    Foo<std::unique_ptr<T>> foo; 
} 

を渡された場合私の理解では、AがBよりも特化しているということであっても、さらに特化しており、使用されたものでなければなりません。しかし、少なくともMSVC 2015ではエラーが発生します:

error C2752: 'Foo<FieldT,void>': more than one partial specialization matches the template argument list 

ここに何か不足していますか?

+0

まあ、2つの 'std :: enable_if'ステートメントは補完的なものでしょうか? –

+0

それはそれを解決するかもしれませんが、私の理解は、 "より特殊化された"ルールは不要にする必要があります。 – Arelius

答えて

3

質問:どの専門技術を使用してfoo<std::unique_ptr<int>>と呼ぶべきですか?

intはクラスではないので、値std::is_class<T>::valueはfalseであり、Aのバージョンは一致しません。

あなたはAバージョンが今まで使用されていることをしたい場合は、最初のテンプレートパラメータがstd::unique_ptrあるとき、あなたは

template <typename T> 
struct foo<std::unique_ptr<T>, 
      typename std::enable_if<std::is_class< 
       std::unique_ptr<T>>::value>::type> 
{ static int const value = 1; }; 

または

template <typename T, 
      typename = typename std::enable_if<std::is_class<T>::value>::type> 
struct foo; 

template <typename T> 
struct foo<std::unique_ptr<T>> 
{ static int const value = 1; }; 

template <typename T> 
struct foo<T> 
{ static int const value = 2; }; 
を次のように fooを書くことができるよう Aバージョンを書くことができます

したがってABよりも特殊なバージョンになり、コードをコンパイルできます。さもなければ、Aのあなたのバージョンは実際にはBですが、コンパイラはそれを認識しないより特殊なバージョンです。

template <typename T> 
struct foo<std::unique_ptr<T>, 
      typename std::enable_if<std::is_class< 
       std::unique_ptr<T>>::value>::type> 
{ static int const value = 1; }; 

コードのコンパイルとそれを観察し、std::is_class<std::unique_prt<T>>::valueこれまで真であること。しかし、あなたは

template <typename T> 
struct foo<std::unique_ptr<T>, 
      typename std::enable_if<true>::type> 
{ static int const value = 1; }; 

(つまり、実際には、同等である)書く場合のコードは、

をコンパイルしていません - EDIT -

あなたはそのfoo<std::unique_ptr<int>マッチケースBをしたい場合は、あなたは(例で)

struct foo<T> 
{ static int const value = 2; }; 

template <typename T> 
struct proValue 
    : std::integral_constant<int, 2> 
{ }; 

template <typename T> 
struct proValue<std::unique_ptr<T>> 
    : std::integral_constant<int, std::is_class<T>::value ? 1 : 2> 
{ }; 

を次のようにタイプの特性を作成し、fooなどを定義することができます以下は、アンリは、彼の答えに言ったことに加えて、完全なコンパイルの例

#include <memory> 
#include <vector> 
#include <iostream> 
#include <type_traits> 

class Test 
{ }; 

template <typename T, 
      typename = typename std::enable_if<std::is_class<T>::value>::type> 
struct foo; 

template <typename T> 
struct foo<std::unique_ptr<T>> 
{ static int const value = 1; }; 

template <typename T> 
struct foo<T> 
{ static int const value = 2; }; 

template <typename T> 
struct proValue 
    : std::integral_constant<int, 2> 
{ }; 

template <typename T> 
struct proValue<std::unique_ptr<T>> 
    : std::integral_constant<int, std::is_class<T>::value ? 1 : 2> 
{ }; 

template <typename T, int = proValue<T>::value> 
struct bar; 

template <typename T> 
struct bar<std::unique_ptr<T>, 1> 
{ static int const value = 1; }; 

template <typename T> 
struct bar<T, 2> 
{ static int const value = 2; }; 

int main() 
{ 
    std::cout << foo<std::vector<int>>::value << '\n';  // print 2 
    std::cout << foo<std::unique_ptr<int>>::value << '\n'; // print 1 
    std::cout << foo<std::unique_ptr<Test>>::value << '\n'; // print 1 

    std::cout << bar<std::vector<int>>::value << '\n';  // print 2 
    std::cout << bar<std::unique_ptr<int>>::value << '\n'; // print 2 
    std::cout << bar<std::unique_ptr<Test>>::value << '\n'; // print 1 
} 
+0

ああそうです。基本的に、コンパイラは、あるバージョンが他のものよりもすべての引数に特化していることを保証しようとしています。 'std :: enable_if :: value> :: type'の型は' std :: enable_if > :: value :: :: type'の特殊化の比較が失敗します! – Arelius

2

エラーを少し再現するための小さな例を設定しました。

#include <iostream> 
#include <memory> 
#include <type_traits> 

template < typename T, typename = void > 
struct foo; 

template < typename T > 
struct foo < std::unique_ptr<T>, 
      typename std::enable_if<std::is_class<T>::value>::type > 
{ 
    static int const value = 1; 
}; 

template < typename T > 
struct foo < T, 
      typename std::enable_if<std::is_class<T>::value>::type > 
{ 
    static int const value = 2; 
}; 

class Test; 

int main() 
{ 
    std::cout << foo< std::unique_ptr<Test> >::value << '\n'; 
} 

私はどのようにコンパイラはあなたではなくT = std::unique_ptr<Test>よりもまず専門とT = Testを推定しているしたいことを知っている必要があり

test.cpp:26:16: error: ambiguous partial specializations of 
     'foo<std::unique_ptr<Test, std::default_delete<Test> >, void>' 
    std::cout << foo< std::unique_ptr<Test> >::value << '\n'; 
      ^
test.cpp:9:8: note: partial specialization matches [with T = Test] 
struct foo < std::unique_ptr<T>, 
    ^
test.cpp:16:8: note: partial specialization matches [with T = std::unique_ptr<Test, 
     std::default_delete<Test> >] 
struct foo < T, 
    ^
1 error generated. 

クランからの誤差がかなり曖昧でないと思いますか?また、どちらの場合もTは、std::enable_ifを無意味にするクラスです。

+0

私はその質問がなぜあいまいであったのかと考えています –

+0

@PasserBy答えは最後の2つの文にあります。コンパイラが2つのケースを明確にするために使用できるものはないので、あいまいです。 – rubenvb

+0

@rubenvb問題は*私の理解は、AはBよりも専門的であり、これは答えられない*であるべきです。 –

1

ある

template <typename T, int = proValue<T>::value> 
struct foo; 

template <typename T> 
struct foo<std::unique_ptr<T>, 1> 
{ static int const value = 1; }; 

template <typename T> 
struct foo<T, 2> 
{ static int const value = 2; }; 

、あなたは(限定的な意味で)ほぼ自明なis_unique_ptrを書き込むことによってこの問題を回避することができ、次の形質。

Live demo here

私はコードに根本的な欠陥があるので省略しました。


あなたは、これはすでに非自明なstd::unique_ptrのために失敗したが、それはis_unique_ptr形質を拡張することによって解決することができるかを見ることができます。実装は、余分な(デフォルトの)テンプレートパラメータを望みどおりに追加することが非常に許可されているので、これは決して水密性にはなりません。

#include <iostream> 
#include <memory> 
#include <type_traits> 

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

template<typename... UniquePtrArgs> 
struct is_unique_ptr<std::unique_ptr<UniquePtrArgs...>> : std::true_type {}; 

template<typename T, typename = void> 
struct foo; 

template<typename... UniquePtrArgs> 
struct foo<std::unique_ptr<UniquePtrArgs...>> 
{ 
    static int const value = 1; 
}; 

template<typename T> 
struct foo<T, typename std::enable_if<!is_unique_ptr<T>::value && std::is_class<T>::value>::type> 
{ 
    static int const value = 2; 
}; 

class Test; 

void f(Test*); 

int main() 
{ 
    std::cout << foo<std::unique_ptr<Test>>::value << '\n'; 
    std::cout << foo<Test>::value << '\n'; 
    std::cout << foo<std::unique_ptr<Test, decltype(&f)>>::value << '\n'; 
} 

Live demo here

より適切な解決策はまたあなたのfooテンプレートの特殊化を変更する必要があります。

std::unique_ptrに特化するのではなく、専門化を活用しているstd::unique_ptrという特定のプロパティを持つタイプを特化する方が賢明かもしれないので、特定のタイプに縛られずに特定のプロパティになります。

+0

ありがとう、私は私のunique_ptrの場合にも、比較でそれを持っている問題を解決して終わったし、基になるTがクラスではない気にしないように実装を変更します。しかし、これも良いかもしれません。 – Arelius

関連する問題