2013-05-15 31 views
2

爲了使用std::tuple構造函數進行單元測試,我想爲構造函數參數生成一個特殊情況樣本和隨機值。假設我有std::tuplestd::vector<T1>std::vector<Tn>(其中每個Ti都不相同),我怎樣才能將它轉換成所有std::tuple<T1, ..., Tn>組合的完整笛卡爾積的std::vector如何使用笛卡爾乘積將矢量元組轉換爲元組矢量?

具體來說,我想有一個可變參數函數模板,看起來是這樣的:

template<typename... Args> 
std::vector<std::tuple<Args...> cartesian_product(std::vector<Args>...) 
{ 
    // template magic or fat mulitple loops? 
} 

,並可以這樣使用:

// some type to be tested 
class MyType 
{ 
    MyType(std::tuple<int, bool, std::string>); 
    // bla 
}; 

// test values for each constructor argument 
std::tuple< std::vector<int>, std::vector<bool>, std::vector<std::string> > input { 
    { 1, 2, 3}, { false, true}, { "Hello", "World"} 
}; 

// should become 3 x 2 x 2 = 12 cases { {1, false, "Hello"}, ... , {3, true, "World"} } 
std::vector< std::tuple<int, bool, std::string> > test_cases = cartesian_product(input); 

// can write flat single loop over all cases 
for (auto t: test_cases) { 
    BOOST_CHECK(MyType(t).my_test()); 
} 

是否有任何(升壓)庫那可以做到這個開箱即用?如何爲此寫入可變參數模板?

+0

@zch很棒,我甚至瀏覽過那個,但不知怎的,它看起來並不像完整的通用解決方案,而是「僅」一個用於2個參數的情況。對不起,錯過了(這看起來很簡單!)。 – TemplateRex

+0

這是一般性的,我會增加第三維作爲例子,使其更清晰(即使它在評論中提到)。 – zch

+0

@zch我測試了它,它完全符合我的要求。真的很酷的把戲。 – TemplateRex

回答

3

http://ideone.com/ThhAoa

不是說技巧:

#include <cstddef> 
#include <utility> 
#include <vector> 
#include <tuple> 
#include <string> 
#include <iostream> 

using std::size_t; 

template<size_t...> struct seq {}; 
template<size_t Min, size_t Max, size_t... s> 
struct make_seq:make_seq< Min, Max-1, Max-1, s... > {}; 
template<size_t Min, size_t... s> 
struct make_seq< Min, Min, s... > { 
    typedef seq<s...> type; 
}; 
template<size_t Max, size_t Min=0> 
using MakeSeq = typename make_seq<Min, Max>::type; 

size_t product_size() { 
    return 1; 
} 
template<typename... Sizes> 
size_t product_size(size_t x, Sizes... tail) { 
    return x * product_size(tail...); 
} 
namespace details { 
    template<typename max_iterator, typename Lambda> 
    void for_each_index(max_iterator mbegin, max_iterator mend, Lambda&& f, std::vector<size_t>& idx) { 
    if (mbegin == mend) { 
     f(idx); 
    } else { 
     for (size_t i = 0; i < *mbegin; ++i) { 
     idx.push_back(i); 
     for_each_index(mbegin+1, mend, f, idx); 
     idx.pop_back(); 
     } 
    } 
    } 
    template<typename Lambda> 
    void for_each_index(std::vector<size_t> const& maxes, Lambda&& f) { 
    std::vector<size_t> idx; 
    details::for_each_index(maxes.begin(), maxes.end(), f, idx); 
    } 
    template<size_t... s, typename... Ts> 
    std::vector< std::tuple<Ts...> > does_it_blend(seq<s...>, std::tuple< std::vector<Ts>... >const& input) { 
    std::vector< std::tuple<Ts...> > retval; 
    retval.reserve(product_size(std::get<s>(input).size()...)); 
    std::vector<size_t> maxes = { 
     (std::get<s>(input).size())... 
    }; 
    for_each_index(maxes, [&](std::vector<size_t> const& idx){ 
     retval.emplace_back(std::get<s>(input)[idx[s]]...); 
    }); 
    return retval; 
    } 
} 
template<typename... Ts> 
std::vector< std::tuple<Ts...> > does_it_blend(std::tuple< std::vector<Ts>... >const& input) { 
    return details::does_it_blend(MakeSeq< sizeof...(Ts) >(), input); 
} 

int main() { 
    std::tuple< std::vector<int>, std::vector<bool>, std::vector<std::string> > input { 
    { 1, 2, 3}, { false, true}, { "Hello", "World"} 
    }; 

    // should become 3 x 2 x 2 = 12 cases { {1, false, "Hello"}, ... , {3, true, "World"} } 
    std::vector< std::tuple<int, bool, std::string> > test_cases = does_it_blend(input); 

    for(auto&& x:test_cases) { 
    std::cout << std::get<0>(x) << "," << std::get<1>(x) << "," << std::get<2>(x) << "\n"; 
    } 
} 

在這裏,我創建一個具有可能的索引的笛卡爾積的功能,然後直接在輸出容器創建的元組。

我也做了保留輸出大小的麻煩。

現在用較少的代碼。

+0

+1感謝您的工作答案!相比於@zch(這是你的行數的40%),它有什麼優勢? – TemplateRex

+0

@rhalbersma那麼,沒有讀過那個。其中一個優點是,我將結果直接放置到輸出「std :: vector」中,而該代碼在第一次檢查時會執行大量的「移動」和「複製」操作。 – Yakk

+0

好吧,我當然接受它,很高興知道它可以以不同的方式完成。 – TemplateRex

1

這有幫助嗎?

#include <vector> 
#include <tuple> 
#include <type_traits> 

template <typename... T> 
struct transpose {}; 

template <typename... T> 
struct transpose<std::tuple<std::vector<T>...>> 
{ 
    using type = std::vector<std::tuple<T...>>; 
}; 

template <typename... T> 
struct transpose<std::vector<std::tuple<T...>>> 
{ 
    using type = std::tuple<std::vector<T>...>; 
}; 

int main() 
{ 
    std::tuple<std::vector<int>, std::vector<bool>> var; 

    static_assert(
     std::is_same< 
      transpose<decltype(var)>::type, 
      std::vector<std::tuple<int, bool>> 
     >::value, "" 
    ); 
} 
+0

轉換類型,但我將如何使用它來轉換我的'main()'函數中的實際值,以及如何將它用於笛卡爾乘積? – TemplateRex

+0

@rhalbersma我會稍後嘗試添加一個編輯。 – 0x499602D2