2017-04-30 59 views
2

我知道我可以在std::vector<>專門assertion_traitsCPPUNIT_ASSERT_EQUAL性病收藏

namespace CPPUNIT_NS 
{ 
    template <class T> struct assertion_traits<std::vector<T>> 
    { 
     inline static bool equal(const std::vector<T>& left, const std::vector<T>& right) 
     { 
      return std::equal(left.begin(), left.end(), right.begin(), assertion_traits<std::vector<T>>::equal); 
     } 

     inline static string toString(const std::vector<T>& vector) 
// etc... 

但是,如果我想CPPUNIT_ASSERT_EQUALunordered_set,我要再寫assertion_traits。我怎樣才能寫出一個assertion_traits,它可以用迭代器處理所有事情?

我猜我需要類似Boosts的範圍概念?

回答

1

什麼

template <template <typename ...> class C, typename ... T> 
struct assertion_traits<C<T...>> 
{ 
    inline static bool equal(C<T...> const & left, C<T...> const & right) 
    { 
     return std::equal(left.begin(), left.end(), right.begin(), 
         assertion_traits<decltype(*(left.begin()))>::equal); 
    } 
}; 

不適用於「帶迭代器的所有東西」(例如:不適用於std::array,因爲有一個不是類型的模板參數),但應攔截很多它們。

一個大問題是,可以攔截沒有迭代器的容器;我建議你遵循W.C.的例子。基於typer的解決方案可以攔截std::array並避免誤報。

無論如何,一個完整的工作示例

#include <vector> 
#include <algorithm> 

template <typename T> 
struct assertion_traits 
{ 
    inline static bool equal (T const & left, T const & right) 
    { return left == right; } 
}; 

template <template <typename ...> class C, typename ... T> 
struct assertion_traits<C<T...>> 
{ 
    inline static bool equal(C<T...> const & left, C<T...> const & right) 
    { 
     return std::equal(left.begin(), left.end(), right.begin(), 
         assertion_traits<decltype(*(left.begin()))>::equal); 
    } 
}; 


int main() 
{ 
    std::vector<int> v1; 

    assertion_traits<std::vector<int>>::equal(v1, v1); 
} 
+0

@JayBazuzi - 你應該告訴我們通用的'assertion_traits';無論如何,從W.F .:看起來比我的好(或者,至少是比我的解決方案更好的基礎) – max66

+0

這有很多幫助:'CPPUNIT_ASSERT_EQUAL'很滿意聲明。但是'std :: equal()'調用無法編譯。 –

+0

http://cppunit.sourceforge.net/doc/1.8.0/struct_cpp_unit_1_1assertion__traits.html –

2

您可以使用別名模板,將SFINAE出類型,而包含傳遞給您的專業如迭代器類型:

#include <vector> 
#include <array> 

template <class> 
struct without_iterator { }; 

template <class T> 
struct X { 
    static constexpr bool value = false; 
}; 

template <class T, class...> 
using typer = T; 

template <class T> 
struct X<typer<T, typename T::iterator>> { 
    static constexpr bool value = true; 
}; 

int main() { 
    static_assert(X<std::vector<int>>::value, "!"); 
    static_assert(X<std::array<int, 4>>::value, "!"); 
    static_assert(!X<without_iterator<int>>::value, "!"); 
    static_assert(!X<int>::value, "!"); 
} 

其中X是你的CPPUNIT_NS::assertion_traits

[live demo]

將它應用到您的解決方案:

template <class T, class...> 
using typer = T; 

namespace CPPUNIT_NS 
{ 
    template <class T> struct assertion_traits<typer<T, typename T::iterator>> 
    { 
     inline static bool equal(const T& left, const T& right) 
     { 
      return std::equal(left.begin(), left.end(), right.begin(), assertion_traits<decltype(*(left.begin()))>::equal); 
     } 

     inline static string toString(const T& vector) 
// etc... 

如果你想你也可以測試開始結束所有腦幹,使您的T肯定接口如預期。如果你願意,甚至可以使用test if T comes from std namespace(至少在某些有限的範圍內)。

編輯:

更安全的辦法是堅持:

template <template <class...> class V, class... Ts> 
struct X<typer<V<Ts...>, typename V<Ts...>::iterator>> { 
    static constexpr bool value = true; 
}; 

即使它不能應用於std::array爲使用struct X<typer<T, typename T::iterator>>可能不是由編譯器爲一體的專業化可以看出X模板,但重新定義Xexample)...

+0

好主意你的'typer';這是我第一次看到SFINAE以這種方式使用;今天我學到了一些新東西。 – max66

+0

@ max66那麼這個想法並不是真的,我在T.C看到了類似的東西。回答(我現在找不到它,也許他刪除了它?),以便可以將std :: hash專門化爲某些模板類型。這真的很瘋狂,但它應該在一些非常特殊的情況下工作......就像OP的問題,我想:)的情況下 –

+0

好主意,無論如何;只有一件事:我糾正了我的答案中的一個錯誤,我想這個錯誤也出現在你的代碼中:你寫'assertion_traits :: equal',但我想應該是'assertion_traits :: equal'(或類似的東西來獲得包含類型的類型;'T'是容器類型;否則可以是'T :: value_type',但我不知道它是否對每個容器有效) – max66