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

[C++]Szablon klasy - metoda wykonująca różne działania w zależności od podanego typu szablonowego

Ostatnio zmodyfikowano 2017-02-12 15:50
Autor Wiadomość
fokusx
Temat założony przez niniejszego użytkownika
[C++]Szablon klasy - metoda wykonująca różne działania w zależności od podanego typu szablonowego
» 2017-02-11 21:34:52
Witam,
mam dany szablon klasy:
C/C++
template < typename T >
class Klasa
{
public:
    void metoda( const T & t )
    {
        //...
    }
};

mam problem z wykonaniem różnych operacji w zależności od podanego typu szablonowego T, przykładowo:
C/C++
void metoda( const T & t )
{
    if( typeid( T ) == typeid( MYINT ) )
    {
        int k = t.dana * t.dana;
    } else if( typeid( T ) == typeid( MYINT2 ) )
    {
        int a = t.dana1 * t.dana2;
    } else
         Log::Write( "" );
   
}

klasa MYINT zawiera 1 zmienną o etykiecie "dana", a klasa MYINT2 2 zmienne o etykietach "dana1", "dana2".
Kompilator pluje się, że MYINT nie zawiera podanych nazw zmiennych, mimo że nie używam (do tej pory) typu szablonowego MYINT (użyta została MYINT2).
Jak rozwiązać problem???
P-157607
mokrowski
» 2017-02-11 21:56:21
1. Dodać szablon do metody
2. Użyć polimorfizmu.
P-157608
fokusx
Temat założony przez niniejszego użytkownika
» 2017-02-11 22:14:02
1. Tylko problem jest taki, że klasa jest szablonowa - wydaje mi się bez sensu nadawanie tego samego typu szablonowego dla metody?
P-157609
michal11
» 2017-02-11 22:18:00
Mam dla ciebie dwa rozwiązania w zależności od tego jaki dokładnie problem chcesz rozwiązać. Przede wszystkim czy dobrze mi się wydaje, że argument funkcji ma być taki sam jak typ parametru klasy? Czyli dla każdego typu dla którego robisz różne zachowanie w tej metodzie musisz mieć oddzielną instancję klasy. W takim wypadku masz tu przykład nr.1
C/C++
#include <iostream>
#include <string>

//====================================================================================================================
template < typename T >
struct Type2Type
{
    typedef T OriginalType;
};

class MyInt
{
public:
    int data;
};

class MyInt2
{
public:
    int data1;
    int data2;
};

template < typename T >
class DoSth
{
public:
    void method( const T & t );
   
private:
    template < typename U >
    void method( const T & t, Type2Type < U > );
   
    void method( const T & t, Type2Type < MyInt > );
   
    void method( const T & t, Type2Type < MyInt2 > );
};

template < typename T >
void DoSth < T >::method( const T & t )
{
    method( t, Type2Type < T >() );
}

template < typename T >
template < typename U >
void DoSth < T >::method( const T & t, Type2Type < U > )
{
    std::cout << "Default";
}

template < typename T >
void DoSth < T >::method( const T & t, Type2Type < MyInt > )
{
    int a = t.data * t.data;
}

template < typename T >
void DoSth < T >::method( const T & t, Type2Type < MyInt2 > )
{
    int k = t.data1 * t.data2;
}

//====================================================================================================================
int main()
{
    MyInt m1;
    m1.data = 10;
   
    MyInt2 m2;
    m2.data1 = 5;
    m2.data2 = 100;
   
    DoSth < int > d1;
    DoSth < MyInt > d2;
    DoSth < MyInt2 > d3;
    DoSth < float > d4;
   
    d1.method( 5 );
    d2.method( m1 );
    d3.method( m2 );
    d4.method( 5.f );
   
    return 0;
}

jeżeli natomiast chcesz mieć swoją metodę która będzie się różnie zachowywać dla różnych argumentów ale w obrębie tej samej instancji klasy to możesz napisać coś takiego:
C/C++
#include <iostream>
#include <string>

//====================================================================================================================
template < typename T >
struct Type2Type
{
    typedef T OriginalType;
};

class MyInt
{
public:
    int data;
};

class MyInt2
{
public:
    int data1;
    int data2;
};

template < typename T >
class DoSth
{
public:
    template < typename V >
    void method( const V & t );
   
private:
    template < typename V, typename U >
    void method( const V & t, Type2Type < U > );
   
    template < typename V >
    void method( const V & t, Type2Type < MyInt > );
   
    template < typename V >
    void method( const V & t, Type2Type < MyInt2 > );
};

template < typename T >
template < typename V >
void DoSth < T >::method( const V & t )
{
    method( t, Type2Type < V >() );
}

template < typename T >
template < typename V, typename U >
void DoSth < T >::method( const V & t, Type2Type < U > )
{
    std::cout << "Default";
}

template < typename T >
template < typename V >
void DoSth < T >::method( const V & t, Type2Type < MyInt > )
{
    int a = t.data * t.data;
}

template < typename T >
template < typename V >
void DoSth < T >::method( const V & t, Type2Type < MyInt2 > )
{
    int k = t.data1 * t.data2;
}

//====================================================================================================================
int main()
{
    MyInt m1;
    m1.data = 10;
   
    MyInt2 m2;
    m2.data1 = 5;
    m2.data2 = 100;
   
    DoSth < int > d1;
   
    d1.method( 5 );
    d1.method( m1 );
    d1.method( m2 );
    d1.method( 5.f );
   
    return 0;
}

chciaż szczerze mówiąc to wydaje mi się, że chciałeś pierwszą wersję to jednak ta druga wydaje mi się bardziej intuicyjna bo przecież jeżeli chcesz traktować specjalnie jakąś klasę w swojej klasie szablonowej to możesz napisać jej specjalizację (klasy) a nie tylko konkretnej funkcji, no ale masz obydwa przykłady. No i moim zdaniem to jest lepsze (bardziej czytelne i schludne) rozwiązanie niż twój if na typeid.
P-157610
j23
» 2017-02-12 11:27:08
A zwykła specjalizacja metody nie wystarczy?
C/C++
template < typename T >
class Klasa
{
public:
    void metoda( const T & t )
    {
        Log::Write( "" );
    }
};

template <> void Klasa < MYINT >::metoda( const MYINT & t )
{
    int k = t.dana * t.dana;
    ...
}

template <> void Klasa < MYINT2 >::metoda( const MYINT2 & t )
{
    int a = t.dana1 * t.dana2;
    ...
}
P-157615
michal11
» 2017-02-12 15:50:48
Można i będzie to lepsze rozwiązanie niż moje (swoją droga tak chciałem zrobić na początku ale coś mi nie wychodziło). Ale niestety to nie zadziała (tak mi się przynajmniej wydaje) jeżeli chcemy aby metoda przyjmowała inny argument niż parametr szablonu klasy, czyli mój drugi przykład.

Edit.

Jeszcze jedna sprawa, sposób ze specjalizacją nie zadziała jeżeli w funkcji będzie więcej niż jeden argument ponieważ nie można częściowo specjalizować funkcji i trzeba wtedy skorzystać z type2type.
P-157617
« 1 »
  Strona 1 z 1