2015-09-09 22 views
3

例如,以鏡像pair < int , float >pair < float , int >,我可以創建一個模板函數是這樣的:是否有通用的方法來鏡像一對(配對<A,B>配對<B,A>)?

template<class AB,class BA> 
void mirror(const AB& ab,BA& ba){ 
    ba.first=ab.second; 
    ba.second=ab.first; 
} 

int main(){ 
    pair<int,float> ab; 
    ab.first=3; 
    ab.second=2.0; 
    pair<float,int> ba; 
    mirror<decltype(ab),decltype(ba)>(ab,ba); 
    printf("%d\n",ba.second); 
    return 0; 
} 

但這種方法不能處理在另一對的一對,例如:

pair < bool , pair< int , float > >pair < pair < float , int > , bool >

pair<bool,pair<int,float> > a_bc; 
pair<pair<float,int>,bool> cb_a; 
mirror<decltype(a_bc),decltype(cb_a)>(a_bc,cb_a); 

pair < pair < A , B >, pair < C , D > >pair < pair < D , C > , pair< B , A > >

pair<pair<A,B>,pair<C,D> > ab_cd; 
pair<pair<D,C>,pair<B,A> > dc_ba; 
mirror<decltype(ab_cd),decltype(dc_ba)>(ab_cd,dc_ba) 

是否可以編寫鏡像模板函數(例如:2個鏡像函數模板,一個用於配對,另一個用於非對,然後使用遞歸),可以處理上述所有情況?

+0

此mehtod即可;噸處理任何T1 = T2,其中T1,T2是類型對 –

+0

的!可能您可以檢測到一個模板參數是否配對(它具有first_type和second_type typedefs),然後您可以進行遞歸調用。但是這實際上並不意味着參數是一對的......我不確定它是否能夠以一種很好和安全的方式解決。 – Melkon

回答

7

您可以創建2個重載:

template<typename T> 
constexpr const T& mirror(const T& t) 
{ 
    return t; 
} 

template<class A, class B> 
constexpr auto mirror(const std::pair<A, B>& p) 
{ 
    return std::make_pair(mirror(p.second), mirror(p.first)); 
} 

Demo

+0

優雅。你可以(或者你需要)使用'decltype(auto)'作爲第一個'mirror'來避免複製嗎? – melak47

+0

@ melak47:返回類型已更改。 – Jarod42

+0

第一個鏡像功能的要點是什麼?爲什麼沒有它,它不工作? – rozina

0

你可以在pair類中實現例如

pair<B, A> swap() { 
    pair<B, A> tmp; 
    tmp->first = this->second; 
    tmp->second = this->first; 
    return tmp; 
} 

只需要時調用它。

+1

它在代碼中並不明顯,但它被標記爲[tag:std-pair],所以我們應該假設源代碼中有一個隱藏的'使用std :: pair'。所以它需要是一個非成員函數。 –

3
template<typename T1, typename T2, typename S1, typename S2> std::pair<std::pair<S2, S1>, std::pair<T2, T1>> 
    mirror(const std::pair<std::pair<T1, T2>, std::pair<S1, S2>>& p) 
{ 
    return std::pair<std::pair<S2, S1>, std::pair<T2, T1>>(mirror(p.second), 
                  mirror(p.first)); 
} 

template<typename T1, typename T2, typename S> std::pair<S, std::pair<T2, T1>> 
    mirror(const std::pair<std::pair<T1, T2>, S>& p) 
{ 
    return std::pair<S, std::pair<T2, T1>>(p.second, mirror(p.first)); 
} 

template<typename T, typename S1, typename S2> std::pair<std::pair<S2, S1>, T> 
    mirror(const std::pair<T, std::pair<S1, S2>>& p) 
{ 
    return std::pair<std::pair<S2, S1>, T>(mirror(p.second), p.first); 
} 

template<typename T, typename S> std::pair<S, T> 
    mirror(const std::pair<T, S>& p) 
{ 
    return std::pair<S, T>(p.second, p.first); 
} 


int main() { 
    pair<bool, pair<int, float> > a_bc; 
    pair<pair<float, int>, bool> cb_a = mirror(a_bc); 

    pair<pair<int, double>, pair<bool, pair<char, float>>> ab__c_de; 
    pair<pair<pair<char, float>, bool>, pair<double, int>> de_c__ab = mirror(ab__c_de); 
} 
+0

@ Jarod42調整了代碼 –

+0

順便說一句,'std :: make_pair'可能會簡化你的代碼。 – Jarod42

0

我想你指的是深,而不是淺,操作 - 的區別,通常用於拷貝,但我想有沒有理由不適用於其他操作。

要實現這一點,您需要模板專門化 - 以瞭解如何鏡像一般類型(什麼都不做)以及如何鏡像std::pair的專用案例。

不幸的是,模板專門化只適用於類,而不適用於獨立函數,因此您需要編寫一個模板類來純粹具有(靜態)成員函數,然後可能使用非專用模板函數來調用該模板類的靜態方法 - 如果你想寫更簡單的調用,而不是擔心類,在其他地方。

以下是一個全面測試的程序,其中包括基於std::pair的基於「深度」轉儲的獎勵模板專業化。

#include <iostream> 
#include <utility> 

template<typename T> struct Mirror // General case 
{ 
    typedef T input_t; 
    typedef T output_t; 

    static T mirror (T p) { return p; } 
    //static T mirror (T &&p) { return std::move (p); } 
}; 

template<typename A, typename B> struct Mirror<std::pair<A,B>> // Special case 
{ 
    typedef typename Mirror<A>::output_t mirror_a_t; 
    typedef typename Mirror<B>::output_t mirror_b_t; 

    typedef std::pair<A,B>     input_t; 
    typedef std::pair<mirror_b_t,mirror_a_t> output_t; 

    static output_t mirror (std::pair<A,B> p) 
    { 
    return std::make_pair (Mirror<B>::mirror (p.second), Mirror<A>::mirror (p.first)); 
    } 
}; 

template<typename T> auto mirror (T p) -> decltype (Mirror<T>::mirror (p)) 
{ 
    return Mirror<T>::mirror (p); 
} 

template<typename T> struct Dump 
{ 
    static void dump (T p, unsigned p_Depth) 
    { 
    for (unsigned i = 0; i < p_Depth; i++) { std::cout << " "; } 
    std::cout << p << std::endl; 
    } 
}; 

template<typename A, typename B> struct Dump<std::pair<A,B>> 
{ 
    static std::pair<A,B> dump (std::pair<A,B> p, unsigned p_Indent) 
    { 
    for (unsigned i = 0; i < p_Indent; i++) { std::cout << " "; } 
    std::cout << "begin first" << std::endl; 
    Dump<A>::dump (p.first, p_Indent + 1); 
    for (unsigned i = 0; i < p_Indent; i++) { std::cout << " "; } 
    std::cout << "end first" << std::endl; 

    for (unsigned i = 0; i < p_Indent; i++) { std::cout << " "; } 
    std::cout << "begin second" << std::endl; 
    Dump<B>::dump (p.second, p_Indent + 1); 
    for (unsigned i = 0; i < p_Indent; i++) { std::cout << " "; } 
    std::cout << "end second" << std::endl; 
    } 
}; 

template<typename T> void dump (T p) 
{ 
    Dump<T>::dump (p, 0); 
} 

int main() 
{ 
    auto x1 = std::make_pair (std::make_pair ("hello", 5), 10.0); 
    auto x2 = mirror (x1); 

    std::cout << "--------------------" << std::endl; 
    std::cout << "Input" << std::endl; 
    std::cout << "-----" << std::endl; 
    dump (x1); 
    std::cout << "--------------------" << std::endl; 
    std::cout << "Output" << std::endl; 
    std::cout << "------" << std::endl; 
    dump (x2); 
    std::cout << "--------------------" << std::endl; 

    return 0; 
} 

輸出...

-------------------- 
Input 
----- 
begin first 
    begin first 
    hello 
    end first 
    begin second 
    5 
    end second 
end first 
begin second 
    10 
end second 
-------------------- 
Output 
------ 
begin first 
    10 
end first 
begin second 
    begin first 
    5 
    end first 
    begin second 
    hello 
    end second 
end second 
-------------------- 

幾點要注意...

  1. 在前面的未經檢驗和破碎的版本,我包括了移動語義一些支持。我在這裏評論過它,因爲我甚至沒有爲其他地方的引用而感到困擾 - 所有事情都是爲了簡單而傳遞價值,並專注於模板專業化。這裏肯定有過多的複製,我沒有打算優化。

  2. 深度反射型std::pair<A,B>通常不是std::pair<B,A>,因爲組件也得到了反射。這就是爲什麼Mirror模板有各種類型定義 - 確定正確的遞歸反射類型。

  3. mirror非成員模板函數使用尾隨返回類型 - 我認爲這是必要的,但TBH我沒有嘗試沒有。

再次感謝Jarod42指出了早期版本中的錯誤之一。最後一個注意事項 - 因爲「深度」操作傾向於儘可能深入地操作,所以如果您處於更大的模板環境中,它們可以比預期更深入。你可以鏡像std::pair基礎的類型,其中您最深切的項目ABC等 - 類型參數模板 - 和忘記,或許AB等本身可能是std::pair情況下(這取決於你的模板調用者),這不應該被鏡像。

這可以通過包裝深層操作障礙的值來處理,但使用淺層操作來構建操作到固定深度的較大半深操作也同樣容易。

對不起。

+1

應該是'template class Mirror >',然後用正確的'std :: pair'替換'T'。 – Jarod42

+0

@ Jarod42 - 沒關係 - 愚蠢的錯誤,易於修復,但我確信那裏有更多愚蠢的錯誤。正如我在即將被刪除的評論中所說的那樣,我不介意任何人將其複製並將其正確地放在自己的答案中 - 如果發生這種情況,我會刪除它。 – Steve314

0

嘗試函數模板重載以支持用於對巢鏡:

template<class AB,class BA> 
void mirror(const AB& ab,BA& ba){ 
    ba = ab; 
} 
template<class A,class B,class C,class D> 
void mirror(const pair<A, B>& a, pair<C, D>& b){ 
    mirror(a.first, b.second); 
    mirror(a.second, b.first); 
} 

LIVE

相關問題