2013-06-30 3 views
6

У меня есть структура, содержащую 3 поле, два int сек (назовем их и В) и bool(С).Тройная карты в том числе 2 ключа

Я хочу создать своего рода массив этой структуры и иметь доступ к нему через любой из ключей (A или B), получая объект отверстия (с A, B и C) взамен. Мне не нужно делать что-то вроде «получения всего объекта, для которого bool истинно», если это имеет значение.

Очевидно, что оба ключа уникальны, и bool не может быть, но я думал, что упомянул об этом ради ясности.

Если бы не было А или В, это было бы просто std::map<int, bool>.

Единственным решением, которое я сейчас вижу, является создание обертки, содержащей 2 set и vector. Есть ли способ облегчить мне жизнь?

NB: В нем будет не более ста кортежей, поэтому производительность не должна быть проблемой. Линейный доступ является приемлемым.

Чтобы сделать это еще более ясным, вот что я хотел бы быть в состоянии сделать:

foobar<int, int, bool> array; // or something along those lines 

array.add(1, 101, true); 
array.add(2, 102, false); 

array.getA(1); // returns first object 
array.getA(2); // returns second object 
array.getB(102); // returns second object again 
+0

Если это ваше реальное требование (int, int, bool), а не пример сокращения, я бы просто сделал это с двумя картами ('map '), один для A и один для B. –

+0

Это сократите пример, но, самое главное, это решение будет В любом случае, обертка должна содержать синхронизацию 2 'bool'. – 1ace

ответ

6

Я считаю, что вы ищете boost::multi_index. Это позволит вам объявить контейнер с несколькими индексами.

struct MultiIDStruct 
{ 
    size_t idA; 
    size_t idB; 
    std::string name; 
}; 

namespace mul = boost::multi_index; 

boost::multi_index_container< MultiIDStruct, 
    mul::indexed_by< 
     mul::ordered_unique< mul::member< MultiIDStruct, size_t, &MultiIDStruct::idA > >, 
     mul::ordered_unique< mul::member< MultiIDStruct, size_t, &MultiIDStruct::idB > > 
    > > data; 

(Используются пространство имен «ярлык» согласно Rapptz предложения)

Например здесь у вас есть multi_index контейнера MultiIDStruct, для которых есть два уникальная упорядоченности, один на idA (который является членом от MultiIDStruct) и второй на idB (который также является членом).

Параметры шаблона сначала кажутся горсткой, но они не так плохи, как только вы понимаете, как они работают.

+2

Вы можете сократить это, выполнив 'namespace mul = boost :: multi_index' или что-то в этом роде. – Rapptz

+0

Это выглядит идеально. У меня будет более глубокий взгляд на это завтра и решить, предпочитаю ли я это или решение RyanMcK. – 1ace

0

Я знаю, что я не давал реализацию деталей. Но я просто предлагаю логику с двумя картами. Что с этим не так? Зачем мне снижаться?

struct s 
{ 
int i; 
int j; 
bool b; 
}; 

std::map<int, int> mapA; 
std::map<int, s> mapB; 

const s& getA(int i) 
{ 
    return mapB[mapA[i]]; 
} 

const s& getB(int j) 
{ 
    return mapB[j]; 
} 

void add(int i, int j, bool b) 
{ 
    s p; 
    p.i=i; 
    p.j=j; 
    p.b=b; 
    mapB[j]=p; 
    mapA[i]=j; 
} 
+0

Я не сторонник, но вы не можете получить цельный объект для 'b'. – soon

+0

@ Что значит «дырокол»? – Immueggpain

+0

Это была опечатка. Целый объект. – soon

1

Предложение разделить его на две карты, конечно, немного проще, но если вы хотите немного больше гибкости и может использовать C++ 11 для функций, таких как std::tuple, вы можете попробовать что-то вида:

#include <iostream> 
#include <map> 
#include <tuple> 

template <typename T1, typename T2, typename T3> 
class foobar 
{ 
public: 
    void add(T1 t1, T2 t2, T3 t3) 
    { 
     m1[t1] = std::make_tuple(t1, t2, t3); 
     m2[t2] = std::make_tuple(t1, t2, t3); 
    } 

    std::tuple<T1,T2,T3> getA(T1 t1) 
    { 
     return m1[t1]; 
    } 

    std::tuple<T1,T2,T3> getB(T2 t2) 
    { 
     return m2[t2]; 
    } 

private: 
    std::map<T1,std::tuple<T1,T2,T3>> m1; 
    std::map<T2,std::tuple<T1,T2,T3>> m2; 
}; 

int main() 
{ 
    foobar<int, int, bool> array; // or something along those lines 

    array.add(1, 101, true); 
    array.add(2, 102, false); 

    auto res1 = array.getA(1); // returns first object 
    auto res2 = array.getA(2); // returns second object 
    auto res3 = array.getB(102); // returns second object again 

    std::cout << std::get<0>(res1) << std::endl; 
    std::cout << std::get<1>(res2) << std::endl; 
    std::cout << std::get<2>(res3) << std::endl; 

    return 0; 
} 

A working example дает выходные данные 1, 102, 0 (false).

+0

Ну, это в значительной степени обертка, которую я имел в виду, хотя я, хотя она была бы намного больше. Благодаря! – 1ace

0

Имея ту же проблему и другое решение!

Имейте две хеш-функции на A и B, давая h1 (A) и h2 (B) такие, что они не дают равных значений.Пример:

uint32_t A; 
uint32_t B; 

uint64_t hashA(uint32_t value) 
{ return ((uint64_t)value) << 32; } 

uint64_t hashB(uint32_t value) 
{ return (uint64_t)value; } 

Поместите все свои вещи в станд :: карту так, чтобы Hasha и hashB имеют одинаковое значение для BOOL. Получите доступ к нему либо с hashA, либо с hashB.

Пример: А = 0x10000001, В = 0x20000002, С = истинная

Hasha (А): 0x1000000100000000 hashB (В): 0x0000000020000002

карта: 0x1000000100000000 -> истинная 0x0000000020000002 -> верно

Смежные вопросы