2017-06-18 29 views
5

我想創建部分專用模板,如果傳遞了一個std::unique_ptrC++模板部分特例 - 最專業用的unique_ptr <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

那麼,兩個'std :: enable_if'語句應該是互補的吧? –

+0

似乎可以解決它,但我的理解是「更專業」的規則應該使這是不必要的。 – Arelius

回答

3

問題:應該使用哪種專業化foo<std::unique_ptr<int>>

注意到int不是一個類,所以值std::is_class<T>::value是假和A版本不匹配。

如果你想使A版本是用過時的第一個模板參數是std::unique_ptr,你可以寫A版本

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

,或者你可以寫foo如下

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

因此A成爲比B更專業化的版本,您的代碼可以編譯。否則,您的版本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是有史以來真正;如果您希望foo<std::unique_ptr<int>相符B

, - 但是,如果你寫

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

(即,其實是相當)的代碼不會編譯

- 編輯可以(通過示例)創建類型性狀如下

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作爲如下

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

下面是一個完整的編譯例子

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

我覺得從鏘錯誤很明確

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 = Test與第一專業化,而不是T = std::unique_ptr<Test>?此外,在這兩種情況下,T是使std::enable_if無意義的類。

+0

我認爲這個問題是爲什麼它不明確 –

+0

@PserserBy答案在最後兩句:它是不明確的,因爲沒有什麼編譯器可以用來消除這兩種情況:它們都是同樣有效的。 – rubenvb

+0

@rubenvb問題是*我的理解是A比B更專業化,應該是使用*的那個,這不會回答。 –

1

除了什麼亨利在他的回答說,你可以(在有限的意義上)解決此寫近瑣碎is_unique_ptr特徵。

Live demo here

我省略了代碼,因爲它有根本的缺陷。


你可以看到這已經失敗了一個不平凡的std::unique_ptr,但可以通過擴展is_unique_ptr特徵來解決。請注意,實現是非常容許添加額外(默認)模板參數,因爲他們希望,所以這永遠不會是一個水密。

更合適的解決方案還包括修改您的foo模板特:

#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

而是專門爲std::unique_ptr的,它可能是更明智的專注於各類與你在專業化借力std::unique_ptr一定的屬性,所以你不依賴於特定的類型,而是一個特定的屬性。

+0

謝謝,我最終解決了這個問題,使得我的unique_ptr案例在比較中也有這樣的問題,然後更改實現以不在意底層T不是類。但是,這本來可以做得很好。 – Arelius