2015-09-09 5 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) 

Возможно ли написать функции шаблона зеркала (например, шаблоны зеркальных функций, один для пары, другой для непарных, а затем использовать рекурсию), которые могут обрабатывать все случаи выше?

+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)' для первого «зеркала», чтобы избежать копирования? – melak47

+0

@ melak47: возврат type изменен. – 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], поэтому мы должны предположить, что в источнике есть скрытая 'using 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

BTW, 'std :: make_pair' может упростить ваш код. – Jarod42

0

Я думаю, что вы имеете в виду глубокие, а не мелкий, операция - различие обычно используются для копий, но я предполагаю, что есть нет причин, по которым он не может применяться к другим операциям.

Для реализации этого вам потребуется специализированная специализация - иметь общий пример того, как зеркалировать общие типы (ничего не делать) и специализированный случай для зеркального отображения std::pair.

К сожалению, специализация шаблона работает только для классов, а не для автономных функций, поэтому вам нужно написать класс шаблона, чтобы иметь (статическую) функцию-член, а затем, возможно, использовать неспециализированную функцию шаблона для вызова этого шаблона class static method - если вы хотите написать более простые вызовы, не беспокоясь о классе, в другом месте.

Ниже приведена полностью протестированная программа, включающая «глубокий» сброс на основе шаблона бонуса на основе 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 имеют различные typedefs - определение правильного рекурсивно-отраженного типа.

  3. Функция шаблона mirror не являющийся членом использует косой тип возвращаемого значения - я думаю это необходимо, хотя ТВНА я не пробовал без него.

Еще раз спасибо Jarod42 за то, что вы указали одну из ошибок в более ранней версии.

Последнее замечание: поскольку «глубокие» операции имеют тенденцию работать настолько глубоко, насколько это возможно, они могут идти глубже, чем вы ожидаете, если вы находитесь в более широком контексте шаблонов. Вы можете зеркалируете -О типа std::pair где ваши глубочайшие элементы являются A, B, C и т.д. - аргументы типа для шаблона - и забывать, что, возможно, A, B и т.д. сам по себе могут быть std::pair экземпляров (в зависимости от шаблонов вызывающего абонента), который не должны быть зеркальным.

Это может быть обработано путем обертывания значений барьерами для глубоких операций, но это может быть так же просто, как использование мелких операций для создания более крупных полу-глубоких операций, которые работают с фиксированной глубиной.

Извините за задержку.

+1

Должно быть 'template class Mirror >', а затем заменить 'T' на правильную' std :: pair'. – Jarod42

+0

@ Jarod42 - Ничего - глупая ошибка, легко исправить, хотя я уверен, что там глупые ошибки. Тем не менее, как я уже сказал в своем комментарии к будущему удалению, я не против, чтобы кто-то копировал это и правильно вложил в него собственный ответ - я удалю это, если это произойдет. – Steve314

0

шаблон функции Try перегрузки поддерживать зеркало гнезда для пары:

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