Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] klasy cech i i szablony jako parametry typu

Ostatnio zmodyfikowano 2016-11-21 17:39
Autor Wiadomość
b00rt00s
Temat założony przez niniejszego użytkownika
[C++] klasy cech i i szablony jako parametry typu
» 2016-11-09 16:41:06
Problem jest jak najbardziej wydumany, ale zależy mi na zrozumieniu pewnego mechanizmu. Oto program (z potrzebnymi komentarzami):

C/C++
#include <map>
#include <set>
#include <type_traits>

using namespace std;

//deklaruje pierwsza klasę cech i definiuje jedną specjalizację
template < typename T >
struct traits_1;

template <>
struct traits_1 < int >
{
    template < typename...Args >
    using type = std::map < Args...>;
};


//deklaruje drugą klasę cech i również definiuje jedną specjalizację
template < template < class...> class _map_ >
struct traits_2;

template <>
struct traits_2 < std::map >
{
    template < typename T >
    using container = std::set < T >;
};

//sprawdzam drugą klasę cech, kod się kompiluje
template < typename T >
using container_type_1 = typename traits_2 < std::map >::container < T >;

//definiuję alias dla wykorzystujący pierwszą klasę cech
template < typename...Args >
using map_type = typename traits_1 < int >::template type < Args...>;

//sprawdzam, czy alias poprawnie zwraca szablon std::map, brak błędu kompilacji, czyli wszystko wydaje się w porządku
static_assert( std::is_same < map_type < int, int >, std::map < int, int >>::value, "typy sa inne" );

//wykorzystuję alias i drugą klasę cech... i kod się nie kompiluje.
template < typename T >
using container_type_2 = typename traits_2 < map_type >::container < T >;


int main( int argc, char * argv[] )
{
    container_type_1 < int > t1;
    container_type_2 < int > t2;
    return 0;
}

Oto błędy kompilacji z kompilatora clang:

main.cpp:43:35: error: implicit instantiation of undefined template 'traits_2<map_type>'
using container_type_2 = typename traits_2<map_type>::container<T>;
                                  ^
main.cpp:21:8: note: template is declared here
struct traits_2;
       ^
main.cpp:43:55: error: expected a qualified name after 'typename'
using container_type_2 = typename traits_2<map_type>::container<T>;
                                                      ^
main.cpp:43:55: error: type-id cannot have a name
using container_type_2 = typename traits_2<map_type>::container<T>;
                                                      ^~~~~~~~~
main.cpp:43:64: error: expected ';' after alias declaration
using container_type_2 = typename traits_2<map_type>::container<T>;
                                                               ^
                                                               ;
main.cpp:49:2: error: no template named 'container_type_2'; did you mean 'container_type_1'?
        container_type_2<int> t2;
        ^~~~~~~~~~~~~~~~
        container_type_1
main.cpp:32:1: note: 'container_type_1' declared here
using container_type_1 = typename traits_2<std::map>::container<T>;
^
main.cpp:46:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char *argv[])
             ^
main.cpp:46:26: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char *argv[])
                         ^
2 warnings and 5 errors generated.

Pytanie brzmi, czemu ten kod kompiluje i jak można go naprawić? Mam wprawdzie swoje podejrzenia, ale nie mam pomysłu co z tym zrobić...
P-153504
Monika90
» 2016-11-09 17:08:45
map_type<K,V,C,A> to jest to samo co std::map<K,V,C,A>,
ale map_type to nie jest to samo co std::map, są to dwa różne szablony.

Można dodać specjalizację dla map_type

C/C++
template <>
struct traits_2 < map_type >
{
    template < typename T >
    using container = std::set < T >;
};

wtedy kod da się skompilować: http:/​/coliru.stacked-crooked.com/a​/0ab76a55cc00f5bd
P-153505
b00rt00s
Temat założony przez niniejszego użytkownika
» 2016-11-09 18:34:00
Tak, to prawda, ale wówczas cała zabawa z klasami cech traci sens. Moim zamysłem było, żeby z klasy traits_1 wydobyć typ szablonowy, który pozwoli wydobyć kolejny typ z klasy traits_2. Wyobraźmy sobie, że dodamy takie dwie specjalizacje:
C/C++
template <>
struct traits_1 < std::string >
{
    template < typename...Args >
    using type = std::multimap < Args...>;
};

template <>
struct traits_2 < std::multimap >
{
    template < typename T >
    using container = std::multiset < T >;
};
oraz gdzieś będziemy chcieli zdobyć wydobyć typ dla klasy std::string, wiec dodamy taki alias:
C/C++
template < typename...Args >
using map_type_2 = typename traits_1 < std::string >::template type < Args...>;
którego użylibyśmy tak:
C/C++
template < typename T >
using container_type_3 = typename traits_2 < map_type_2 >::container < T >;

Pytanie, czy takie coś jest w ogóle możliwe? Jakimś innym sposobem oczywiście ;)
P-153514
Monika90
» 2016-11-09 19:18:57
Nie wiem po co jest ten pośrednik map_type_2?

A może tak?
C/C++
#include <map>
#include <set>
#include <string>

template < template < class...Args > class T >
struct alias
{
    template < class...Args >
    using type = T < Args...>;
};

template < class >
struct traits_1;

template <>
struct traits_1 < std::string >
{
    using type = alias < std::multimap >;
};

template < class >
struct traits_2;

template <>
struct traits_2 < alias < std::multimap >>
{
    template < class T >
    using container = std::multiset < T >;
};

int main()
{
    traits_2 < traits_1 < std::string >::type >::container < int > x; //x jest typu std::multiset<int>
}
P-153517
Monika90
» 2016-11-09 19:55:45
Albo tak?
C/C++
#include <map>
#include <set>
#include <string>
#include <type_traits>

template < class >
struct traits_1;

template <>
struct traits_1 < std::string >
{
    template < class...Args >
    using type = std::multimap < Args...>;
};

template < template < class...> class, class = void >
struct traits_2;

template < template < class...> class T >
struct traits_2 < T, std::enable_if_t < std::is_same < std::multimap < int, int >, T < int, int >>::value >>
{
    template < class U >
    using container = std::multiset < U >;
};

int main()
{
    traits_2 < traits_1 < std::string >::type >::container < int > x;
}
P-153518
b00rt00s
Temat założony przez niniejszego użytkownika
» 2016-11-21 17:39:31
Dzięki, te przykłady działają.
P-153988
« 1 »
  Strona 1 z 1