[C++] template: 'specjalizacja' funkcji

0

Mój problem przedstawia się następująco:
Potrzebna mi funkcja do pobierania jednego z dwóch wskaźników znajdujących się w klasie (tylko jeden ze wskaźników != NULL, oba są różnego typu).
Funkcja ma działać tylko dla dwóch typów ewentualnie dla innych może zwracać wskaźnik NULL. Moją alternatywą jest napisanie funkcji przyjmujących jako parametr wskaźnik danego typu i do tego wskaźnika przypisanie odpowiedzi.

Próbowałem to zrobić w następujący sposób:

template <> ConnData* getData<ConnData>(void) throw () {
    return this->connData1; //klasa ConnData*
}

lub

template <ServerData T> T* getData(void) throw () {
    return this->connData2; //klasa ServerData*
}

Oba sposoby nie są poprawne. Czy istnieje jakiś sposób na zrobienie tego poprawnie?

Moja klasa:

class Conn{
public:
    template <typename T> T* getData(void) throw ()  {
        return NULL;
    };
    template <> ConnData* getData<ConnData>(void) throw () {
        return this->connData1; //klasa ConnData*
    };
    template <ServerData T> T* getData(void) throw () {
        return this->connData2; //klasa ServerData*
    };
private:
    ConnData *connData1;
    ServerData *connData2;
};
0

Specjalizacje metod dajesz za szablonem (u Ciebie w ogóle go nie ma), czyli:

class Conn
{
public:
        // wersja ogólna... 
        template <typename T> T* getData(void) throw ()  { ... }
 
        // ... i specjalizacje
        template <> ConnData* getData<ConnData>(void) throw ()   { ... }
        template <> ServerData* getData<ServerData>(void) throw ()   { ... }
0

Mój błąd nie podałem szablonu, ale on jest. :)
Ten sposób generuje błąd:

error: explicit specialization in non-namespace scope 'class Conn'
error: template-id 'getData<ConnData>' in declaration of primary template
 

Btw. kompiluje g++ z MinGW 4.5.0.

0

jak widac, komunikat mowi, ze nie mozna umieszczac specjalizacji inline. przenies cialo specjalizacji funkcji poza cialo klasy, a'la:

template<typename U> class X
{
    template<typename T> U method(T arg);
};

// partial spec: T=Foo
template<typename U> U X<U>::method<Foo>(Foo arg)
{
    kod kod kod kod;
}

// partial spec: U=Bar
template<typename T> Bar X<Bar>::method<T>(T arg)
{
    kod kod kod kod;
}

// full spec: T=Foo U=Bar
template<typename U> Bar X<Bar>::method<Foo>(Foo arg)
{
    kod kod kod kod;
}

niestety poprawnosci nie gwarantuje, kompilatora C++ nie mam pod reka

0
/////Conn.h
class Conn
{
    template<typename T> T* getData(void);
};

/////Conn.cpp
template<typename T> T* Conn::getData(void)
{
    return NULL;
}

// partial spec: T=ConnData
template<> ConnData* Conn::getData<ConnData>(void)
{
    return new ConnData();
}

// partial spec: T=ServerData
template<> ServerData* Conn::getData<ServerData>(void)
{
    return new ServerData();
}

Wprowadziłem kilka poprawek aby rozwiązanie pasowało do kryteriów:
-klasa nie potrzebuje template'u
-funkcja nie przyjmuje parametrów

Dla podanego kodu dostaję:

Conn.cpp:8: error: specialization of 'template<class T> T* Conn::getData()' in different namespace
Conn.h:4: error:   from definition of 'template<class T> T* Conn::getData()'
Conn.cpp:14: error: specialization of 'template<class T> T* Conn::getData()' in different namespace
Conn.h:4: error:   from definition of 'template<class T> T* Conn::getData()'

Po takich zmianach nie mogę doprowadzić tego kodu do stanu w którym będzie kompilowalny.

Czy specjalizacja funkcji jest możliwa?

0

Implementacje metod (szablonowych) powinny być w pliku nagłówkowym. Póki co szablonów nie możesz dzielić pomiędzy pliki h i cpp.

0

Przeniosłem do pliku .h:

/////Conn.h
class Conn
{
    template<typename T> T* getData(void);

    ConnData* Conn::getData<ConnData>(void)
    {
        return new ConnData();
    }
};

Rezultat:
Conn.h:6: error: template-id 'getData<ConnData>' in declaration of primary template

0

Ech, sharkos, czytasz w ogóle, co się do Ciebie pisze?

class Conn
{
    template<typename T> T* getData(void);
};

template<typename T> T* Conn::getData(void) { ... }

template<> ConnData* Conn::getData<ConnData>(void)
{
    return new ConnData();
}

// itd...

To wszystko w jednym pliku nagłówkowym.

0

Moja wina za szybko napisałem.

Teoretycznie działa, ale linker ma problem:
Conn.h:

#ifndef CONN_H_INCLUDED
#define CONN_H_INCLUDED

#include <string>
namespace nm{
    class ConnData{
        public:
        ConnData(){};
        ~ConnData(){};
        int id;
    };
    class ServerData{
        public:
        ServerData(){};
        ~ServerData(){};
        std::string id;
    };
    class Conn{
        public:
        Conn();
        ~Conn();
        ConnData* con1;
        ServerData* con2;
        template<typename T> T* getData();
    };
    template<> ConnData* Conn::getData(){
        return this->con1;
    };
}
#endif // CONN_H_INCLUDED

Conn.cpp:

#include "Conn.h"
nm::Conn::Conn(){
    this->con1 = NULL;
    this->con2 = NULL;
}
nm::Conn::~Conn(){
}

Rezultat:

Linking console executable: ..\lib\mingw\Client.exe
..\Temp\codeblocks\netmod\Release\Conn.o:Conn.cpp:(.text+0x0): multiple definition of `nm::ConnData* nm::Conn::getData<nm::ConnData>()'
..\Temp\codeblocks\netmod\Release\main.o:main.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Błąd pojawił się po dodaniu pliku .cpp, oryginalna klasa Conn jest o wiele bardziej rozbudowana, w przykładzie .cpp wydaje się niepotrzebny.

0

Dobra, zrób tak:

// conn.h

...

class Conn
{
        ...
        template<typename T> T* getData();
};

template<> ConnData* Conn::getData<ConnData>();
template<> ServerData* Conn::getData<ServerData>();

// conn.cpp

template<> ConnData* Conn::getData<ConnData>()
{
        return this->con1;
}

template<> ServerData* Conn::getData<ServerData>()
{
        return this->con2;
}
0

Dzięki, działa.
Rozwiązanie problemu:

Conn.h:

#ifndef CONN_H_INCLUDED
#define CONN_H_INCLUDED

#include <string>
namespace nm{
    class ConnData{
        public:
        ConnData(){};
        ~ConnData(){};
        int id;
    };
    class ServerData{
        public:
        ServerData(){};
        ~ServerData(){};
        std::string id;
    };
    class Conn{
        public:
        Conn();
        ~Conn();
        ConnData* con1;
        ServerData* con2;
        template<typename T> T* getData();
    };
    template<> ConnData* Conn::getData();
    template<> ServerData* Conn::getData();
}
#endif // CONN_H_INCLUDED

Conn.cpp:

#include "Conn.h"
nm::Conn::Conn(){
    this->con1 = NULL;
    this->con2 = NULL;
}
nm::Conn::~Conn(){
}
template<> nm::ConnData* nm::Conn::getData(){
    return this->con1;
}
template<> nm::ServerData* nm::Conn::getData(){
    return this->con2;
}

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