carlosmay Temat założony przez niniejszego użytkownika |
Klasa szablonowa zarządzana enum'em w zależności od typu kontenera » 2016-05-22 00:08:50 Dla każdego kontenera osobno kod się kompiluje i działa prawidłowo. Natomiast kod w całości nie chce działać. Wydaje mi się, że nieprawidłowo wykrywa Type, gdy są oba kontenery. Nie wiem jak to ugryźć. #include <iostream> #include <set> #include <map>
class ComponentType { public: enum class eType { map, vector, set, simple }; };
template < typename Type > class Show { const ComponentType::eType mode; public: Show( ComponentType::eType m ) : mode( m ) { } void FillComponent( Type & comp ) { if( mode == ComponentType::eType::map ) { comp.insert( { 2, 6 } ); comp.insert( { 8, 6 } ); } else if( mode == ComponentType::eType::set ) { comp.insert( { 7 } ); comp.insert( { 4 } ); } } void PrintComponent( const Type & comp ) { if( mode == ComponentType::eType::map ) { for( const auto & item: comp ) { std::cout << item.first << " : " << item.second << '\n'; } std::cout << '\n'; } else if( mode == ComponentType::eType::set ) { for( const auto & item: comp ) { std::cout << item << ' '; } std::cout << '\n'; } } };
int main() { using Map = std::map < int, int, std::less < int >>; using Set = std::set < int, std::less < int >>; Map m; Set s; Show < Map > map( ComponentType::eType::map ); map.FillComponent( m ); Show < Set > set( ComponentType::eType::set ); set.FillComponent( s ); map.PrintComponent( m ); set.PrintComponent( s ); } |
|
Monika90 |
» 2016-05-22 09:00:24 Nie da się tak zrobić. W C++ obydwie gałęzie if-else muszą zawierać poprawny kod. Nawet jeżeli wartość warunku if jest znana w czasie kompilacji. Dlatego należy użyć przeciążonych funkcji #include <iostream> #include <set> #include <map>
void FillComponent( std::map < int, int > & comp ) { comp.insert( { 2, 6 } ); comp.insert( { 8, 6 } ); }
void FillComponent( std::set < int > & comp ) { comp.insert( { 7 } ); comp.insert( { 4 } ); }
template < class T > void PrintItem( const T & item ) { std::cout << item << ' '; }
template < class T, class U > void PrintItem( const std::pair < T, U >& item ) { std::cout << item.first << " : " << item.second << '\n'; }
template < class Type > void PrintComponent( const Type & comp ) { for( const auto & item: comp ) { PrintItem( item ); } std::cout << '\n'; }
int main() { using Map = std::map < int, int, std::less < int >>; using Set = std::set < int, std::less < int >>; Map m; Set s; FillComponent( m ); FillComponent( s ); PrintComponent( m ); PrintComponent( s ); }
|
|
Monika90 |
» 2016-05-22 10:23:29 Można też zrobić to tak #include <iostream> #include <set> #include <map>
template < bool cond > struct static_if;
template <> struct static_if < true > { template < class Func1, class Func2 > static auto get( Func1 f1, Func2 ) { return f1; } };
template <> struct static_if < false > { template < class Func1, class Func2 > static auto get( Func1, Func2 f2 ) { return f2; } };
class ComponentType { public: enum class eType { map, vector, set, simple }; };
template < typename Type, ComponentType::eType mode > class Show { public: void FillComponent( Type & comp ) { static_if < mode == ComponentType::eType::map >::get( []( auto & comp ) { comp.insert( { 2, 6 } ); comp.insert( { 8, 6 } ); }, []( auto & comp ) { comp.insert( { 7 } ); comp.insert( { 4 } ); } )( comp ); } void PrintComponent( const Type & comp ) { static_if < mode == ComponentType::eType::map >::get( []( auto & comp ) { for( const auto & item: comp ) { std::cout << item.first << " : " << item.second << '\n'; } std::cout << '\n'; }, []( auto & comp ) { for( const auto & item: comp ) { std::cout << item << ' '; } std::cout << '\n'; } )( comp ); } };
int main() { using Map = std::map < int, int, std::less < int >>; using Set = std::set < int, std::less < int >>; Map m; Set s; Show < Map, ComponentType::eType::map > map; map.FillComponent( m ); Show < Set, ComponentType::eType::set > set; set.FillComponent( s ); map.PrintComponent( m ); set.PrintComponent( s ); }
Ale sam widzisz, że to bez sensu. |
|
carlosmay Temat założony przez niniejszego użytkownika |
» 2016-05-22 14:15:01 W C++ obydwie gałęzie if-else muszą zawierać poprawny kod. |
Już rozumiem. Piszę kod cały obiektowy. Nie chciałem pisać osobnej klasy dla każdego kontenera o odmiennym sposobie (wypisywania) wstawiania elementów. To jest tylko próbna klasa (nazwy nie adekwatne do funkcjonalności). Miło by było dla oka ustawiać enum'em. Dzięki za wskazówki. |
|
carlosmay Temat założony przez niniejszego użytkownika |
» 2016-08-06 02:35:00 Dzięki za pomoc. Rozwiązałem to w ten sposób. Może ktoś skorzysta. #include <iostream> #include <type_traits> #include <set> #include <map> #include <vector> #include <string>
struct UnknownType { }; struct InsertType { }; struct PushBackType { };
template < class Type > struct InserterType { using type = UnknownType; };
template < class Type, class Compare, class Alloc > struct InserterType < std::set < Type, Compare, Alloc >> { using type = InsertType; };
template < class Key, class Value, class Compare, class Alloc > struct InserterType < std::map < Key, Value, Compare, Alloc >> { using type = InsertType; };
template < class Type, class Alloc > struct InserterType < std::vector < Type, Alloc >> { using type = PushBackType; };
template < class Container, class ValueType > void myInsert( InsertType, Container & coll, ValueType && value ) { coll.insert( std::forward < ValueType >( value ) ); }
template < class Container, class ValueType > void myInsert( PushBackType, Container & coll, ValueType && value ) { coll.push_back( std::forward < ValueType >( value ) ); }
template < class Container > void myInsert( Container & coll, typename std::decay_t < Container >::value_type value ) { using DeducedInserterCollectionType = typename InserterType < std::decay_t < Container >>::type; myInsert( DeducedInserterCollectionType { }, coll, std::move( value ) ); }
int main() { std::map < int, std::string > mis = { { 1, " pierwszy wpis" } }; std::set < int > si = { 1, 2, 3 }; std::vector < int > vi { 4, 5, 6 }; myInsert( mis, { 2, " drugi wpis" } ); myInsert( mis, { 3, " trzeci wpis" } ); myInsert( si, 11 ); myInsert( si, 13 ); myInsert( vi, 44 ); myInsert( vi, 55 ); for( auto const & element: mis ) { std::cout << element.first << element.second << '\n'; } for( auto const & element: si ) { std::cout << element << ' '; } std::cout << '\n'; for( auto const & element: vi ) { std::cout << element << ' '; } std::cout << '\n'; }
|
|
michal11 |
» 2016-08-06 12:11:25 Jak rozumiem chciałeś zrobić uniwersalną funkcję do wrzucania elementów do kontenera, jestem na telefonie wiec nie mogę tego dokładnie sprawdzić, ale czy nie mogłeś użyć do tego iteratorów ? Edit. Ja zrobiłem coś takiego: #include <iostream> #include <vector> #include <map> #include <set> #include <iterator>
template < class Container > void myInsert( Container & x, typename Container::value_type && value ) { x.insert( std::end( x ), value ); }
int main() { std::map < int, std::string > mis = { { 1, " pierwszy wpis" } }; std::set < int > si = { 1, 2, 3 }; std::vector < int > vi { 4, 5, 6 }; myInsert( mis, { 2, " drugi wpis" } ); myInsert( mis, { 3, " trzeci wpis" } ); myInsert( si, 11 ); myInsert( si, 13 ); myInsert( vi, 44 ); myInsert( vi, 55 ); for( auto const & element: mis ) { std::cout << element.first << element.second << '\n'; } for( auto const & element: si ) { std::cout << element << ' '; } std::cout << '\n'; for( auto const & element: vi ) { std::cout << element << ' '; } std::cout << '\n'; return 0; }
Niestety nie mogę porównać outputu bo twój kod mi się nie kompiluje (gcc version 5.3.1 na http://www.tutorialspoint.com/codingground.htm) ale wątpię, żeby nie działało tak jak chcesz. |
|
carlosmay Temat założony przez niniejszego użytkownika |
» 2016-08-06 20:41:22 Niestety nie mogę porównać outputu bo twój kod mi się nie kompiluje |
Piszę w VS, a on rządzi się swoimi prawami. Przyznam, że nie wpadłem na takie rozwiązanie. Obecnie, bardziej przyda mi się moje rozwiązanie. Twoje rozwiązanie michal11 warto zapamiętać. edit: zrobiłem test zapisu do kontenerów i użycie struktur daje czas trzy razy krótszy niż użycie iteratora. W C::B na gcc 5.1.0 różnica jest mniejsza, ale nadal na korzyść struktur. int main() { constexpr std::size_t nLoops = 10000000; using TimePoint = std::chrono::high_resolution_clock::time_point; std::map < int, std::string > mis = { { 1, " pierwszy wpis" } }; std::set < int > si = { 1, 2, 3 }; std::vector < int > vi { 4, 5, 6 }; TimePoint start = std::chrono::high_resolution_clock::now(); for( std::size_t i = 0; i < nLoops; ++i ) { myInsert( mis, { 2, " drugi wpis" } ); myInsert( mis, { 3, " trzeci wpis" } ); myInsert( si, 11 ); myInsert( si, 13 ); myInsert( vi, 44 ); myInsert( vi, 55 ); } TimePoint stop = std::chrono::high_resolution_clock::now(); std::cout << std::chrono::duration_cast < std::chrono::duration < double >>( stop - start ).count() << " s" << '\n'; }
vs: 0,7s struct - 2,4s iterator gcc: 7,3s struct - 9,3s iterator |
|
« 1 » |