2014-10-21 6 views
5

Mam klasy jakWywołanie metody zliczania std :: zestaw wskaźników z kluczowego const odniesienia typu

struct S { 

    bool foo(const AType& v) const { 
     return values.count(&v); // compile error due to the constness of v 
    } 

    private: 
     std::set<AType*> values; 
}; 

Jest to uproszczona wersja. W prawdziwym kodzie, foo robi pewne skomplikowane rzeczy. Kod produkuje błąd

invalid conversion from ‘const AType*’ to ‘std::set<AType*>::key_type {aka AType*}’ 

myślę foo powinno „const Atype & v”, ponieważ nie mutują v. typ zmiennej składowej „wartości” nie można std :: set < const AType * > ponieważ niektóre metody struktury S nazywają niestałe metody elementów zawartych w "wartościach". mogę rzucić constness od „v” z dala:

bool foo(const AType& v) const { 
    return values.count((AType*) &v); 
} 

Ale myślę, że to może nie być dobrym rozwiązaniem w ogóle. Jakie rozwiązanie mogę mieć?

+0

Nie widzę nic złego w korzystaniu z 'values.count (const_cast (&v));' skoro masz zamiar porównać tylko wskazówki. –

+1

samo jak zwykle wskaźnik irytacji w '*' const T nie jest zamienny do 't * const i vice versa –

+0

Czy jesteś pewien, że chcesz policzyć po wskaźnikach, ale nie o wartości obiektu? – mirt

Odpowiedz

0
template<class T> 
struct const_ptr_compare:std::less<T const*> { 
    typedef void is_transparent; 
}; 

std::set<AType*, const_ptr_compare<AType>> values; 

i Bob jest twoim wujem.

Zdefiniowałem komparator, który może przezroczyście poradzić sobie z porównaniami T const* oraz T*. Powiedziałem wtedy std::set, że jest przezroczysty.

Technika is_transparent jest ulepszeniem C++ 14 do std::set. Twój kompilator może już mieć na to wsparcie.


Jeśli chcesz być w stanie przejść w klasach bazowych-of T nieco więcej pracy do zrobienia. Potrzebujesz obiektu funkcji, który testuje swoje dwa argumenty (każdy ze wskaźników do const), aby zobaczyć, która klasa bazowa jest drugą i czy używa tej klasy bazowej. To jednak idzie dalej w króliczej dziurze, niż potrzebujemy.


C++ 3/11 podejście mogłoby polegać na utworzeniu edycji porcje ATypemutable, posiadające const AType*set. Jeśli to nie zadziała, rozsądne jest wykonanie const_cast<AType*>.

Proszę nie używać obsady w stylu C: prawie nigdy nie są wymagane i mogą być przypadkowo zbyt potężne.

0

Sedno problemu jest to,

typ „wartości” zmiennej element nie może być std :: zestaw, gdyż niektóre sposoby Struct rozmowy S const metod elementami zawarte w "wartościach".

Nie należy w żaden sposób modyfikować ustawionego klucza.

Powinieneś używać map, gdzie rzeczywiste kluczowe części są w kluczu i są const, a części mutujące są w wartości i nie są const.

Jeśli jest to niepraktyczne dla twojego projektu, rozumiem. Rozwiązanie obejścia const_cast rozwiąże problem. Czuje się nieelegancko, ale to dlatego, że korzystanie z set jest nieeleganckie.

0

To tylko jeden z wielu problemów związanych z koncepcją poprawności stałej: nie skaluje się według kompozycji.

Rozwiązanie odlewania jest w porządku, jeśli uważasz, że jest "brudne" w pewien sposób prawdopodobnie przesadzasz z czystością koncepcji const.

Uważają, że definiowanie specjalnych typów dla const_iterator i const_reverse_iterator był potrzebny lub że czasami const poprawności wymaga kodu rzeczywistego powielania (na przykład w wielu przypadkach do operator[]) lub, że jeśli masz obiekt zawierający non-const wskaźnik można zmutować wskazywał na obiekt swobodnie, a nawet usuwał go w elementach stałych.

Twoja obsada nie wygląda tak źle w porównaniu :-)

Powiązane problemy