DejaVu Temat założony przez niniejszego użytkownika |
[SFML 2] sf::Packet i zabronienie użycia operatora << dla określonego typu » 2013-11-14 21:54:29 Chciałbym zabronić użycie operatora << dla klasy sf::Packet dla określonego typu. Czy da się osiągnąć opisany przeze mnie efekt tak, aby błąd był rzucany już na poziomie kompilacji, bez konieczności ingerowania w implementację SFML-a? Przykład: #include <SFML/Network/Packet.hpp>
class CPacketType { friend void operator <<( sf::Packet &, const CPacketType & ) { throw std::logic_error( "Nie można używać operatora << do zapisywania CPacketType - użyj metody CPacketType::save" ); } };
Powyższy przykład rzuca wyjątkiem w chwili wywołania operatora, a mi chodzi o to, aby na poziomie kompilacji wykryć już nieprawidłowe użycie klasy. |
|
Monika90 |
» 2013-11-15 00:26:57 Zależy o co ci dokładnie chodzi. Możesz zwyczajnie nie zadeklarować tego operatora i program się nie skompiluje. Jeżeli zależy ci na konkretnym komunikacie o błędzie, to być może to zadziała: template < class T = int > void operator <<( sf::Packet &, const CPacketType & ) { static_assert( !sizeof( T ), "Miejsce na twoj komunikat" ); }
|
|
maly |
» 2013-11-15 07:06:46 |
|
DejaVu Temat założony przez niniejszego użytkownika |
» 2013-11-15 10:09:01 Jeżeli nie zadeklaruję wspomnianego operatora, to klasa sf::Packet użyje operatora TypeE operator() const, który jest w klasie CPacketType i tym samym zapisany zostanie int do pakietu. W przypadku zdefiniowania operatora << w powyższym kodzie uzyskuję więc poprawną sytuację, czyli obsługa operatora sf::Packet<< zostaje przechwycona przez dopisany operator. /edit: Alternatywnym rozwiązaniem jest napisanie obsługi w ten sposób: friend bool operator <<( sf::Packet & _packet, const CPacketType & _pt ) { return _pt.save( _packet ); }
Niemniej jednak obecnie intryguje mnie, czy na poziomie kompilacji da się zabronić użycia jakiegoś operatora zdefiniowanego w innej klasie. |
|
Monika90 |
» 2013-11-15 12:30:09 Jeżeli nie zadeklaruję wspomnianego operatora, to klasa sf::Packet użyje operatora TypeE operator() const, który jest w klasie CPacketType i tym samym zapisany zostanie int do pakietu. |
Czy chodzi ci o operator konwersji na jakiś typ całkowitoliczbowy? Nie deklaruj takich operatorów, a jeśli już to z atrybutem explicit. Ale podane przeze mnie wyżej rozwiązanie powinno działać nawet w obecności takiego operatora. bool operator <<( sf::Packet & _packet, const CPacketType & _pt ) |
Zwracanie bool z takiego operatora to zły pomysł. Prędzej czy później ktoś napisze: sf_packet << packet_type << 5; i się zdziwi... Niemniej jednak obecnie intryguje mnie, czy na poziomie kompilacji da się zabronić użycia jakiegoś operatora zdefiniowanego w innej klasie. |
Bez modyfikacji tej klasy? - nie sądzę by istniała jakaś pewna w 100% metoda i wątpię by to było potrzebne. |
|
Elaine |
» 2013-11-15 14:09:27 Najlepszym rozwiązaniem jest niedefiniowanie operatorów konwersji. Ale jeśli już muszą być, to da się to osiągnąć nawet w starych kompilatorach osbługujących tylko C++03 — dla nowszych wystarczy rozwiązanie Moniki — tylko trzeba się trochę pobawić ze SFINAE: #include <ostream>
template < bool P, typename T > struct enable_if;
template < typename T > struct enable_if < true, T > { typedef T type; };
template < typename Base, typename T > struct is_same_or_base { typedef char yes[ 2 ]; typedef char no[ 1 ]; static yes * test( Base * ); static no * test(...); static const bool value = sizeof( * test( static_cast < T *>( 0 ) ) ) == sizeof( yes ); };
template < typename Base, typename T > const bool is_same_or_base < Base, T >::value;
struct Foo { operator int() const { return 5; } };
struct Bar : Foo { };
struct Qux : Bar { };
template < typename T > typename enable_if < is_same_or_base < Foo, T >::value, std::ostream &>::type operator <<( std::ostream & foo, const T & ) { typedef char error_do_not_use_this_function[ sizeof( T ) != 0 ? - 1 : 1 ]; error_do_not_use_this_function x; static_cast < void >( x ); return foo; }
std::ostream & operator <<( std::ostream & foo, const Qux & ) { return foo; }
void foo( std::ostream & stream ) { Foo obj; stream << obj; Bar obj2; stream << obj2; Qux obj3; stream << obj3; } Jeśli używasz Boosta, to zamiast enable_if i is_same_or_base możesz użyć boost::enable_if i boost::is_base_of. |
|
DejaVu Temat założony przez niniejszego użytkownika |
» 2013-11-15 14:21:12 bool operator <<( sf::Packet & _packet, const CPacketType & _pt )
Zwracanie bool z takiego operatora to zły pomysł. Prędzej czy później ktoś napisze: sf_packet << packet_type << 5; i się zdziwi...
|
U nas w projekcie jest wymaganie, że praca z pakietem sprowadza się do:
bool bValid = true; bValid = bValid &&( _packet << 123 );
Poza tym metoda CPacketType::save nie zawsze wykona operację zapisu jeżeli stan obiektu jest niepoprawny, więc wydaje mi się, że jest to jedyny sposób, aby zapobiec zapisaniu danych w błędnym formacie, które przechowuje CPacketType :) |
|
« 1 » |