2012-11-06 78 views
2

可能重複:
Pretty-print std::tuple翻譯(1-元組到10元組)參數n元組參數在C++ 11

在數據庫庫(SOCI),有一段代碼在std::tuple<>的一個到十個參數下工作。

靜態類方法from_base()to_base()被實現爲1元組到10元組的參數。

Guts基本上將每個n元組元素流入和流出傳入的流。一切都是硬編碼的。

如何將此代碼翻譯爲使用C++ 11的可變參數模板(不限參數)? 實際上使用variadic模板或不是次要的。我們真正想要做的是用n元論的一般情況來替代硬編碼。

問題的一部分是,在技術上只有一個參數,但該參數是一個n元組,因此我不能完全使用描述的here in Wikipedia。什麼是最好的方法?

#include "values.h" 
#include "type-conversion-traits.h" 
#include <tuple> 

namespace soci 
{ 

template <typename T0> 
struct type_conversion<std::tuple<T0> > 
{ 
    typedef values base_type; 

    static void from_base(base_type const & in, indicator ind, 
     std::tuple<T0> & out) 
    { 
     in 
      >> std::get<0>(out); 
    } 

    static void to_base(std::tuple<T0> & in, 
     base_type & out, indicator & ind) 
    { 
     out 
      << std::get<0>(in); 
    } 
}; 

template <typename T0, typename T1> 
struct type_conversion<std::tuple<T0, T1> > 
{ 
    typedef values base_type; 

    static void from_base(base_type const & in, indicator ind, 
     std::tuple<T0, T1> & out) 
    { 
     in 
      >> std::get<0>(out) 
      >> std::get<1>(out); 
    } 

    static void to_base(std::tuple<T0, T1> & in, 
     base_type & out, indicator & ind) 
    { 
     out 
      << std::get<0>(in) 
      << std::get<1>(in); 
    } 
}; 

// ... all the way up to 10 template parameters 

} 

RUNNABLE ANSWER(基於以下灰熊的帖子)

#include <iostream> 
#include <tuple> 

using namespace std; 

// ----------------------------------------------------------------------------- 

template<unsigned N, unsigned End> 
struct to_base_impl 
{ 
    template<typename Tuple> 
    static void execute(Tuple& in, ostream& out) 
    { 
     out << std::get<N>(in) << endl; 
     to_base_impl<N+1, End>::execute(in, out); 
    } 
}; 

template<unsigned End> 
struct to_base_impl<End, End> 
{ 
    template<typename Tuple> 
    static void execute(Tuple& in, ostream& out) 
    { 
     out << "<GAME OVER>" << endl; 
    } 
}; 

// ----------------------------------------------------------------------------- 

template <typename Tuple> 
struct type_conversion 
{ 
    static void to_base(Tuple& in, ostream& out) 
    { 
     to_base_impl<0, std::tuple_size<Tuple>::value>::execute(in, out); 
    } 
}; 

template <typename... Args> 
struct type_conversion<std::tuple<Args...>> 
{ 
    static void to_base(std::tuple<Args...>& in, ostream& out) 
    { 
     to_base_impl<0, sizeof...(Args)>::execute(in, out); 
    } 
}; 

// ----------------------------------------------------------------------------- 

main() 
{ 
    typedef tuple<double,int,string> my_tuple_type; 
    my_tuple_type t { 2.5, 5, "foo" }; 

    type_conversion<my_tuple_type>::to_base(t, cerr); 
} 
+0

另請參閱[this](http://stackoverflow.com/a/7858971/726300)和[this](http://stackoverflow.com/q/687490/500104)。 – Xeo

回答

5

如果我正確理解你的問題,你基本上需要調用分別從運營商<<>>爲每個元素你元組。在這種情況下,你可以使用部分專業化和遞歸構建類似for循環的東西(排序的,因爲它每一次實際上是調用不同的功能):

template<unsigned N, unsigned End> 
struct to_base_impl { 
    template<typename Tuple> 
    void execute(Tuple& in, base_type& out) { 
     out<<std::get<N>(in); 
     to_base_impl<N+1, End>::execute(in, out); 
    } 
}; 

template<unsigned End> 
struct to_base_impl<End, End> { //End of loop 
    template<typename Tuple> 
    void execute(Tuple& in, base_type& out) {} 
}; 

template <typename Tuple> 
struct type_conversion 
{ 
    typedef values base_type; 

    static void to_base(Tuple& in, base_type & out, indicator & ind){ 
     to_base_impl<0, std::tuple_size<Tuple>::value>::execute(in, out); 
    } 
}; 

這會從零迭代的元組的大小並且每次迭代調用out<<std::get<N>(in);from_base將以與in>>std::get<N>(out);相同的方式執行。如果你想確保你的轉換器只調用元組可以使用可變參數模板:

template <typename... Args> 
struct type_conversion<std::tuple<Args...>> 
{ 
    typedef values base_type; 

    static void to_base(std::tuple<Args...>& in, base_type & out, indicator & ind){ 
     to_base_impl<0, sizeof...(Args)>::execute(in, out); 
    } 
}; 

當然,你可以寫這個更一般地,但是,這將使源要複雜得多,可能不會給你很多回報。

+1

[It works](http://liveworkspace.org/code/4342f4edd8e09840bd1ae569894a78e3),+1。 – jrok

+0

非常棒 - 兩步過程非常棒! – kfmfe04

+0

@jrok +1對於不錯的緊身示例 – kfmfe04

3

我喜歡indices trick

template<unsigned...> struct seq{}; 
template<unsigned N, unsigned... Is> 
struct gen_seq : gen_seq<N-1, N-1, Is...>{}; 
template<unsigned... Is> 
struct gen_seq<0, Is...> : seq<Is...>{}; 

template<class T> using Alias = T; 

template<class... Ts, unsigned... Is> 
void to_base(std::tuple<Ts...> const& t, base_type& out, seq<Is...>){ 
    Alias<char[]>{ (void(out << std::get<Is>(t)), '0')... }; 
} 

template<class... Ts, unsigned... Is> 
void to_base(std::tuple<Ts...> const& t, base_type& out){ 
    to_base(t, out, gen_seq<sizeof...(Ts)>{}); 
} 

與同爲from_base。 (Live example based on jrok's.

代碼「攻擊」的可變參數拆包機制調用out << get<Is>(t)恰好sizeof...(Is)(這是一樣的sizeof...(Ts))次。 gen_seq<N>生成從0N-1seq<0, 1, 2, ..., N-1>)的編譯時整數列表。該清單保存到unsigned... Is,然後解壓到get<Is>(t)get<0>(t),get<1>(t),一直到get<N-1>(t)
Alias<char[]>{ ... }(臨時數組)提供了可以使用數據包擴展的上下文。我在這裏特別選擇了數組初始化,因爲保證了傳遞參數的從左到右的評估。 (void(expression), '0')將評估expression,丟棄該值並將'0'作爲初始值設定項(​​用於強制選擇內置逗號運算符,而不是任何可能的重載運算符)。

+0

對於不同的搭配+1(以及帶有詳細解釋的不錯鏈接) – kfmfe04