Jak wyspecjalizować metodę w klasie innym sposobem niż tag dispatching

0

Witam
Od C++11 można użyć tag dispatching jak niżej. A co było przed C++11? Dało się wyspecjalizować jakoś jedną metodę w klasie bez definicji nowej klasy?

#include <stdio.h>
#include <iostream>
#include <type_traits>

using namespace std;

template<class T, int N>
class Klasa
{
    public:
       Klasa(const T& t):mT(t){}
       T metoda(const T& t);
    protected:
    T mT;
};

template<class T, int N>
T Klasa<T, N>::metoda(const T& t)
{
    if(is_floating_point<T>::value)
        cout << "float T specialization: " << t << endl;
    else
        cout << t << endl;
    return mT;
}

int main()
{
    cout << Klasa<unsigned, 7>(8).metoda(5) << endl;
    cout << Klasa<float, 7>(8).metoda(5) << endl;

    return 0;
}
0

To wyżej jednak jest źle bo w runtimie jest wybór metody. A to niżej z enable_if i is_same mi sie nie kompiluje mimo że wszystko jest dobrze to dostaje error:

main.cpp:44:1: error: prototype for 'typename std::enable_if::value, void>::type Klasa::metoda(const T&)' does not match any in class 'Klasa'
 Klasa<T, N>::metoda(const T& t)
 ^
main.cpp:37:6: error: candidate is: void Klasa::metoda(const T&)
 void Klasa<T, N>::metoda(const T& t)
      ^

Implementacja:

template<class T, int N>
class Klasa
{
    public:
       Klasa(const T& t):mT(t){}
       void metoda(const T& t);
    protected:
    T mT;
};

template<class T, int N>
void Klasa<T, N>::metoda(const T& t)
{
    cout << t << endl;
}

template<class T, int N>
typename enable_if<is_same<T, float>::value, void>::type //to zwraca void
Klasa<T, N>::metoda(const T& t)
{
    cout << "float T specialization: " << t << endl;
}


int main()
{
    Klasa<unsigned, 7>(8).metoda(5);
    Klasa<float, 7>(8).metoda(5);

    return 0;
}
0

Jeszcze tak próbowałem (jako że partly specialization jest możliwe tylko dla klas) ale też nie działa, wywala: error: invalid use of incomplete type 'class Klasa':

template<int N>
class Klasa<float, N>;

template<int N>
void Klasa<float, N>::metoda(const float& t)
{
    cout << "float T specialization: " << t << endl;
}
0

Jeszcze też tak próbowałem, ale też nie działa. Ale to niżej to już powinno działać bo to jest technika częściowej specjalizacji klasy szablonowej. a wyświetla error: main.cpp13: error: wrong number of template arguments (1, should be 2)

/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <stdio.h>
#include <iostream>
#include <type_traits>
#include <vector>

using namespace std;

template<class T, int N>
class Klasa
{
    public:
       Klasa(const T& t):mT(t){}
       void metoda(const T& t);
    protected:
    T mT;
};

template<class T, int N>
void Klasa<T, N>::metoda(const T& t)
{
    cout << t << endl;
}

template<int N>
class Klasa<float, N>
{
    public:
       Klasa(const float& t):mT(t){}
       void metoda(const float& t);
    protected:
        float mT;
};

template<int N>
void Klasa<N>::metoda(const float& t)
{
    cout << "float implementation: " << t << endl;
}

int main()
{
    Klasa<unsigned, 10>(8).metoda(5);
    Klasa<float>(8).metoda(5);

    return 0;
}
0

ok to jest przykład działający, jak ktoś wie jak zrobić to lepiej po bożemu to prosze dać znać

template<class T, int N>
class Klasa
{
    public:
       Klasa(const T& t):mT(t){}
       void metoda(const T& t);
    protected:
    T mT;
};

template<class T, int N>
void Klasa<T, N>::metoda(const T& t)
{
    cout << t << endl;
}

template<int N>
class Klasa<float, N>
{
    public:
       Klasa(const float& t):mT(t){}
       void metoda(const float& t)
       {
           cout << "float implementation: " << t << endl;
       }
    protected:
        float mT;
};

int main()
{
    Klasa<unsigned, 10>(8).metoda(5);
    Klasa<float, 10>(8).metoda(5);

    return 0;
}
0

Od C++11 można użyć tag dispatching jak niżej. A co było przed C++11?

Przed C++11 było C++03, gdzie też można było używać tag dispatch. Poniżej masz napisany na kolanie przykład, który będzie działać tak samo na 03 i 11.
URUCHOM WANDBOX

#include <iostream>

struct true_type {typedef true_type type;};
struct false_type {typedef false_type type;};

template<bool FLAG>
struct TrueFalseTag : public true_type {};

template<>
struct TrueFalseTag<false> : public false_type{};

template<int N>
struct IsIntBiggerThan5Trait : public TrueFalseTag<(N > 5)>
{};

template<int N>
struct MyClass
{
   int result()
   {
     return resultImpl(N, typename IsIntBiggerThan5Trait<N>::type());
   }
   
   int resultImpl(int n, true_type)
   {
     std::cout << n << " resultImpl true_type\n";
     return n;
   }
   
   int resultImpl(int n, false_type)
   {
     std::cout << n << " resultImpl false_type\n";
     return n;
   }
};

int main()
{
    MyClass<4> tmp4;
    MyClass<6> tmp6;
    tmp4.result();
    tmp6.result();
}

Różnica między 03 i 11 w tym konkretnym przykładzie polega na tym, że masz kilka dodatkowych narzędzi dostępnych już w bibliotece i nie musisz, przykładowo, ręcznie pisać true_type false_type.

1 użytkowników online, w tym zalogowanych: 0, gości: 1