2012-08-11 9 views
6

Czy to jest prawidłowe C++ (biorąc pod uwagę najnowszy standard)? Dostaję błędy kompilacji z clangiem near-top-of-tree/libC++ na Ubuntu 12.04. Jeśli to powinno być ważne, wyślę listę clang-dev z komunikatami o błędach i takimi.Czy element o nazwie unordered_set <reference_wrapper <Ty>> jest prawidłowy?

#include <functional> 
#include <unordered_set> 

struct X 
{ 
    int i; 
}; 

void f() 
{ 
    std::unordered_set<std::reference_wrapper<X>> setOfReferencesToX; 

    // Do stuff with setOfReferencesToX 
} 

** Tak na marginesie, jestem zmęczony kwalifikacyjna, że ​​pytanie/odpowiedź jest specyficzne dla najnowszego standardu. Czy społeczność C++ jako całość powinna zamiast tego zacząć kwalifikować rzeczy, które są specyficzne dla starego standardu? Nowszy standard jest dostępny od około roku.

+1

+1 za notatkę końcową. – Griwes

+0

"Czy społeczność C++ jako całość powinna zamiast tego zacząć kwalifikować rzeczy, które są specyficzne dla starego standardu?" Nie. Biorąc pod uwagę ogromną liczbę użytkowników, którzy nie są w stanie dokonać aktualizacji do kompilatora z bardziej kompletną obsługą C++ 11, nie mówiąc już o popularności pewnej rodziny kompilatorów, która tylko powoli aktualizuje obsługę C++ 11, C++ idzie oznaczać C++ 03 przez co najmniej kolejny rok, jeśli nie dwa. I nie zapominajmy, że ani GCC, ani Clang nie deklaruje pełnej zgodności z C++ 11. Przyszłość nie jest teraźniejszością i udawanie, że tak się nie stanie. –

Odpowiedz

8

Problem nie jest specyficzny dla std::reference_wrapper<T>, ale raczej dla samego typu X.

Problem polega na tym, że std::unordered_set wymaga zdefiniowania funktorów mieszania i równości dla std::reference_wrapper<X>. Możesz przekazać funkcję mieszającą jako drugi parametr szablonu.

Na przykład, to będzie działać:

#include <functional> // for std::hash<int> 

struct HashX { 
    size_t operator()(const X& x) const { 
    return std::hash<int>()(x.i);  
    } 
}; 

a następnie

std::unordered_set<std::reference_wrapper<X>, HashX> setOfReferencesToX; 

Innym rozwiązaniem jest zrobienie specjalizacji dla std::hash<X>:

namespace std { 
template <> 
struct hash<X> { 
    size_t operator()(const X& x) const { 
    return std::hash<int>()(x.i);  
    } 
}; 
} 

To pozwala uniknąć wyraźnie określając drugi argument szablonu:

std::unordered_set<std::reference_wrapper<X>> setOfReferencesToX; 

Jeśli chodzi o porównanie równość, problem ten można rozwiązać poprzez zapewnienie operatorowi równości dla klasy X:

struct X 
{ 
    bool operator==(const X& rhs) const { return i == rhs.i; } 
    int i; 
}; 

W przeciwnym razie, można zdefiniować własne funktor i przekazać go jako trzeci argument szablonu.

+0

Czy nie specjalizowanie 'std :: hash' byłoby nieco prostsze? – Griwes

+0

Byłby, jeśli chcesz umieścić rzeczy w przestrzeni nazw 'std'. – juanchopanza

+0

Nie sądzę, że powinien on być kwalifikowany jako "umieszczanie rzeczy w' std' ", ponieważ jest to zwykła specjalizacja ... – Griwes

Powiązane problemy