Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Специализрованные методы шаблонного класса


Автор: orlangur86 28.2.2010, 02:09
Доброго времени суток!
Объясните пожалуйста, если есть возможность, следующую ситуацию.
Имеется шаблон класса, определенный в файле SomeTpl.h
Выглядит следующим образом:
Код

#pragma once

template< class Tp >
class SomeTpl{
private:
    int var1;
public:
    void some_op1();
    void some_op2();

    int getVar();
};
#include "SomeTpl.inl"

Фактические определения методов в файле SomeTpl.inl
Код

template< class Tp >
int SomeTpl<Tp>::getVar()
{
    return var1;
}

template< class Tp >
void SomeTpl<Tp>::some_op1()
{
    var1 = 1;
}

template< class Tp >
void SomeTpl<Tp>::some_op2()
{
    var1 = 2;
}

template<>
void SomeTpl<int>::some_op1()
{
    var1 = 3;
}

template<>
void SomeTpl<int>::some_op2()
{
    var1 = 4;
}


Как видно из кода, определения включают также специализацию методов some_op1 и some_op2 для типа int.
Есть некий файл SomeCpp1.cpp внутри которого выполнено простое включение

#include "SomeTpl.h"

и ничего более.

И есть файл TestPrj.cpp следующего содержания
Код

#include "stdafx.h"
#include <iostream>

#include "SomeTpl.h"

int _tmain(int argc, _TCHAR* argv[])
{
    SomeTpl<double> x1;
    //SomeTpl<int> x2;

    x1.some_op1();
    std::cout<<x1.getVar()<<std::endl;

    //x2.some_op1();
    //std::cout<<x2.getVar()<<std::endl;
}

Как видно, явно инстанцируется только версия класса для типа double. Ликовщик ругается и говорит, что
1>TestPrj.obj : error LNK2005: "public: void __thiscall SomeTpl<int>::some_op1(void)" (?some_op1@?$SomeTpl@H@@QAEXXZ) already defined in SomeCpp1.obj
1>TestPrj.obj : error LNK2005: "public: void __thiscall SomeTpl<int>::some_op2(void)" (?some_op2@?$SomeTpl@H@@QAEXXZ) already defined in SomeCpp1.obj
В асм. листинге кода для TestPrj присутствует код для SomeTpl<int>::some_op1 и SomeTpl<int>::some_op2
т.е. специализация для int тоже вдруг оказывается инстанцированной, хотя об этом никто не просил. Почему так получается?

Если задать отдельную специализацию для класса в таком виде:
Код

template<>
class SomeTpl<int>{
private:
    int var1;
public:
    void some_op1()
    {
        var1 = 3;
    }
    void some_op2()
    {
        var1 = 4;
    }

    int getVar(){ return var1; }
};

то это прокатывает, но приходится дублировать уже написанное. Как с этим быть? Может я что-то не так понимаю?

Заранее мерси smile

Автор: baldina 28.2.2010, 02:46
Потому что в заголовках можно определять только inline функции, иначе имеем в каждой единице трансляции копию функции.
Цитата

специализация для int тоже вдруг оказывается инстанцированной, хотя об этом никто не просил

не вдруг. не только не просил, а в явном виде определил функции smile

короче - перед каждой функцией в SomeTpl.inl надо поставить inline или определить эти функции в отдельном .cpp

Автор: orlangur86 28.2.2010, 11:18
baldina,  спасибо!
С inline-ом получилось. А вот на счет объявления специализаций в отдельном срр я не понял. Перенес эти специализации в отдельный SpecCpp.cpp
Код

#include "stdafx.h"

#include "SomeTpl.h"

template<>
inline void SomeTpl<int>::some_op1()
{
    var1 = 3;
}

template<>
inline void SomeTpl<int>::some_op2()
{
    var1 = 4;
}


компилятор ругается
speccpp.cpp(9) : error C2908: explicit specialization; 'void SomeTpl<Tp>::some_op1(void)' has already been instantiated
        with
        [
            Tp=int
        ]
speccpp.cpp(15) : error C2908: explicit specialization; 'void SomeTpl<Tp>::some_op2(void)' has already been instantiated
        with
        [
            Tp=int
        ]

где он уже успел инстанцировать эти методы для типа int? 

Автор: baldina 28.2.2010, 17:50
в SpecCpp.cpp они должны быть не inline. "где он успел" обычно компилятор пишет. возможно осталась строчка #include "SomeTpl.inl" в SomeTpl.h

вот так:
Код

// SomeTpl.h
template< class Tp >
class SomeTpl{
private:
    int var1;
public:
    void some_op1();
    void some_op2();
    int getVar();
};


Код

// SomeTpl.cpp
#include <SomeTpl.h>
template<>
void SomeTpl<int>::some_op1()
{
    var1 = 3;
}
template<>
void SomeTpl<int>::some_op2()
{
    var1 = 4;
}


Код

// test.cpp
#include <iostream>
#include "SomeTpl.h"
int main ()
{
    SomeTpl<double> x1;
    //SomeTpl<int> x2;
    x1.some_op1();
    std::cout<<x1.getVar()<<std::endl;
    //x2.some_op1();
    //std::cout<<x2.getVar()<<std::endl;
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)