Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Компиляция заголовочных файлов


Автор: IOnic 13.12.2005, 02:28
Вопрос: имплементация шаблонных функций (членов классов) в .h файле влечет за собой включение тела функции (а не ссылки на нее) в бинарнике? Если нет, то применимо ли "inline" для того чтобы компилятор включал тело функции-члена шаблонного класа? (среда VS2003) Невероятных размеров спасибо!

Автор: Earnest 13.12.2005, 19:13
1) Инстационируется только то, что реально вызывается.
2) Все остальное - то же, что для нешаблонных классов, т.е. напишешь inline - будет inline, нет - будет только одно тело где-нибудь (в пределах исполняемого модуля). Если хочешь экспортировать шаблонную функцию из DLL, это надо делать явно.

Автор: Guest 13.12.2005, 19:35
Earnest
Подскажи, как шаблонную функцию включить в dll ?

Автор: IOnic 13.12.2005, 20:50
Цитата
1) Инстационируется только то, что реально вызывается.
2) Все остальное - то же, что для нешаблонных классов, т.е. напишешь inline - будет inline, нет - будет только одно тело где-нибудь (в пределах исполняемого модуля). Если хочешь экспортировать шаблонную функцию из DLL, это надо делать явно.

... насчет этого я в курсе. А вот есть ли разница между имплементацией в .h и в .cpp с точки зрения бинарника? Другими словами, равносильна ли имплементация функции добавлению "inline" к этой функции в .cpp? Пример - stdlib: std::vector, std::pair, и т.д. Там все в .h. Вобщем не только из-за этого есть подозрения. Я видел кучу исходников в которых небольшие шаблонные классы были полностью в .h в отличии от "тяжелых" (те же параметры шаблонов). Так что вопрос остается открытым...

Автор: Earnest 13.12.2005, 20:54
Шаблонную функцию в DLL не включишь, только ее конкретную реализацию для конкретных параметров.
Цитата(Earnest @ 13.12.2005, 19:13)
Если хочешь экспортировать шаблонную функцию из DLL, это надо делать явно.

Извини, видимо, ввела тебя в заблуждение неточной фразой. Имела в виду, что шаблонную функцию для каких-то параметров можно явно инстационировать в каком-то модуле заранее.

Автор: Earnest 13.12.2005, 21:05
Цитата(IOnic @ 13.12.2005, 20:50)
А вот есть ли разница между имплементацией в .h и в .cpp с точки зрения бинарника?

Разница в том, что тела шаблонных функций, написанные в cpp, недоступны для других частей программы, а, стало быть, бесполезны как общедоступные шаблоны. Конечно, никто не мешает включить cpp файл директивой #include, но мы ведь не об этом говорим? smile

Реализация шаблонов в cpp-файлах имеет смысл в двух случаях:
1) класс совершенно локальный, и используется ровно в том модуле, где нарисован.
2) шаблоны достаточтно тяжелые для засовывания в Н-файл (например, много связей тянут), но заранее известно, что они будут использоваться только с заданным небольшим числом параметров. Тогда их нужно явно инстационировать для этих параметров.

Цитата(IOnic @ 13.12.2005, 20:50)
Другими словами, равносильна ли имплементация функции добавлению "inline" к этой функции в .cpp?

нет, если функция не имплементирована прямо внутри объявления класса.

Автор: IOnic 13.12.2005, 21:05
айайай... я чуток загнул smile . stdlib тут не причем, там просто по-другому никак. А вот насчет остального - правда. Имел ввиду класы с явной инстанциацией - как float и double. Так вот, там где много вычислений - там имплементация происходит в .cpp, а где нет или мало - там в .h. Как обяснить?

Автор: Earnest 13.12.2005, 21:12
Так, я уже не понимаю, чего ты не понимаешь... smile

Автор: IOnic 13.12.2005, 21:13
Цитата
нет, если функция не имплементирована прямо внутри объявления класса.

Вот оно! Тоесть, ДА, если мы определяем название функции, типы аргументов, и сразу же за этим пишем тело???

Автор: Earnest 13.12.2005, 21:17
... то это инлайн.
Ну ты и спрашиваешь! smile
Добавлено @ 21:17
Если, конечно, оно не виртуал...

Автор: IOnic 13.12.2005, 21:24
тоесть инлайн не используя кейворд "инлайн". Это меня и интересовало (я не проф. прогаммер, даже на курсы не ходил, и в Страуструпе насчет этого ничего не нашел). Сенкс! smile
Добавлено @ 21:25
Цитата
прогаммер
- оговорка по дяде Фрейду. smile
Earnest спасибо!

Автор: threef 14.12.2005, 14:32
Инлайн функции либо обьявляются inline, либо записываются в тело класса. При этом, если в ней присутствуют циклы, статические переменные, рекурсия, switch или в программе есть применение адреса этой функции, то компилятор не сделает ее inline. Зато может сделать другую, при указании на оптимизацию по скорости и учитывая ограничения выше. inline никак не связаны с шаблонами. Прекомпиляция заголовков снижает затраты на проверку синтаксиса и вставку файлов.
Шаблоны компилируются только для конкретных параметров, поэтому они и "плавают" в заголовочных файлах целиком - шаблон не может быть откомпилирован в виде шаблона и в таком виде помещен в библиотеку. Это, наверное, и есть причина того, что в MS VS удобнее использовать "родные" MFC-классы коллекций, чем коллекции STL.

Автор: Earnest 15.12.2005, 08:26
Цитата(threef @ 14.12.2005, 14:32)
При этом, если ... в программе есть применение адреса этой функции, то компилятор не сделает ее inline.

Это не совсем так. Т.е., конечно, для таблицы виртуальных функций или аргумента-указателя на функцию генерируется "тело", но в местах прямого вызова, если связывание статическое, вполне может быть выполнена inline-подстановка. Так что даже виртуальные функции стоит делать inline (если они короткие): по крайней мере вызов типа base_class::function внутри перекрытого метода будет инлайн.
Цитата
Это, наверное, и есть причина того, что в MS VS удобнее использовать "родные" MFC-классы коллекций, чем коллекции STL.

Вот уж странное заявление. Если кому и удобнее использовать MFC-коллекции, так только в силу привычки и нежелания отказываться от хорошо знакомого. STL-коллекции имеют более естественную семантику (взять хотя бы эти уродские псевдоитераторы MFC GetPrevPos\GetNextPos), они гибче и уж конечно "стандартнее".

Автор: Гость_Medved 16.12.2005, 22:22
Подскажите чайнику. Пишу программу на Microsoft Visual Studio . NET Professional 2003 :

#include <iostream>
int main()
{
cout << "Hello.\n";
return 0;
}

Вот какую ошибку он выдает :

unable to start debbuging.
unable to start programm 'c\documents and settings\...\мои документы\visual studio progects\1\debug\1.exe'

Автор: threef 20.12.2005, 11:14
Цитата
Earnest Дата 15.12.2005, 08:26

Цитата (threef @ 14.12.2005, 14:32)
При этом, если ... в программе есть применение адреса этой функции, то компилятор не сделает ее inline.


Это не совсем так. Т.е., конечно, для таблицы виртуальных функций или аргумента-указателя на функцию генерируется "тело", но в местах прямого вызова, если связывание статическое, вполне может быть выполнена inline-подстановка...даже виртуальные функции стоит делать inline (если они короткие):

Код


class A{
public:
    virtual void next();
};
inline void A::next()
    {
      cout<<"nextA\n";
    }
class B:public A{
public:
    void next()
    {
      cout<<"nextB\n";
    }
};
void main()
{
            A *a=new B;
            A* c=new A;
            c->next();
            a->next();
            delete a;
            delete c;
}




При чем здесь виртуальные функции ? Если обьект "с " будет статическим, то компилер сделает функцию A::next встроенной; как только появляется использование указателя на функцию, будь то статический вызов или через динамический обьект - тело функции обязательно появится. Чем не статический вызов ?
Код

inline void function()
{
    cout<<"function\n";
}
void main()
{
                void (*f)()=function;
                f();
}



Автор: Earnest 20.12.2005, 15:44
Цитата(threef @ 20.12.2005, 11:14)
как только появляется использование указателя на функцию, будь то статический вызов или через динамический обьект - тело функции обязательно появится


Статический или динамический объект - не важно, ты путаешь.
Я говорила о статическом связывании, т.е. связывании времени компиляции - в противоположность связыванию run-time.

Если сделать твой пример (вызов функции по указателю) более реальным (разнести в коде присвоение и вызов), будет связывание run-time - т.к. непосредственно в точке вызова нельзя определить какая функция будет вызвана в момент компиляции.



Автор: threef 20.12.2005, 19:40
Конкретно в моем примере связывание статическое ?

Автор: Earnest 21.12.2005, 08:07
Формально - нет (вызов по указателю). Но оптимизатор может сообразить, что указателю только что присвоили адрес конкретной функции, и подставить прямой вызов. (Честно говоря, не знаю - есть ли реально такая оптимизация.)
Но не в этом суть: одна и та же функция (в т.ч. виртуальная) может вызываться как статически, так и динамически. В первом случае, если она объявлена инлайн, может быть выполнена подстановка, во втором - нет.


Автор: threef 24.12.2005, 10:12
Очень хотелось бы узнать, у кого такой умный оптимизатор. WATCOM? FARLAP ? Intel ? А пример кода есть ? Я имею в виду откомпилированный+MAP.

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