LINUX.ORG.RU

Разъясните механизм template в С++


0

0

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

Во-первых, если у меня в двух файлах A.cc и B.cc есть объявления (реализации) классов типа такого

class A{
private:
int n;
public:
A():n(0){}
A(int N):n(N){}
// можно еще какую-нибудь фигню приписать
};

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

С template-ами ситуация совсем иная. Отправить объявление типа:

template<class T>
class A{
private:
T n;
public:
A():n(0){}
A(T N):n(N){}
// можно еще какую-нибудь фигню приписать
};

в два различных файла, и там и там сделать A<int> -- и все будет прекрасно работать.

Соответственно, вопрос в том, а как оно так сделано?

> class A{ > private: > int n; > public: > A():n(0){} > A(int N):n(N){} > // можно еще какую-нибудь фигню приписать > };

> тогда линковшик начнет ругаться, что, в принципе, и понятно.

в той форме в которой ты написал, нет, непонятно. И ругаться не будет.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

функции объявленные внутри класса считаются inline. А inline функции могут быть объявлены одинаковые в разных единицах трансляции.

Вот если не inline, тогда да, парадокс.

dilmah ★★★★★
()

> тогда линковшик начнет ругаться

А он точно начнет ругаться? Это только декларации и inline, линковщик их просто не видит.

tailgunner ★★★★★
()

Епта, как все замучено. Недаром нормальные люди обходят этот cpp стороной.

Oceanborn
()
Ответ на: комментарий от dilmah

>Вот если не inline, тогда да, парадокс.

Никакого парадокса. Линковщик С++ обязан удалять дубликаты инстанциированых шаблонов. А способ отличить дубликат полученный включением одного и того же шаблона через #include в два разных .cpp файла от copy/paste одного и того же шаблона в те же два файла навскидку придумать тяжело.

Absurd ★★★
()

vsb-laptop% cat test.cpp
template <typename T>
void template_function(T) {
}

inline void inline_function() {
}

void noninline_function() {
    template_function(1);
    template_function(1.0);
    inline_function();
}

vsb-laptop% g++ -c test.cpp
vsb-laptop% nm test.o
00000000 W _Z15inline_functionv
00000000 W _Z17template_functionIdEvT_
00000000 W _Z17template_functionIiEvT_
00000000 T _Z18noninline_functionv
         U __gxx_personality_v0

символы для inline и шаблонных функций помечены как Weak, поэтому они могут встречаться более одного раза
в разных объектных файлах при конечной линковке. nonline_function не может.

Legioner ★★★★★
()

Собственно, высказавшиеся уже ответили, я могу только перефразировать.

В случае с шаблонами, типичной является ситуация, когда одно определение шаблона включается в разные единицы трансляции. При этом если у компилятора нет возможности сделать методы шаблона inline, то он должен сгенерировать такой код, чтобы линковщик, встретив тело одного и того же метода в разных объетных файлах, - не ругался. Это обсепечивается weak символами.

Ситуация, описанная Вами, для компилятора идентична ситуации, в которой одно и то же определение класса-шаблона включается в несколько единиц трансляции. Тот факт, что на самом деле определения этого класса могут различаться, - говорит о том, что GCC можно обмануть: для классов-шаблонов технически он не в состоянии проконтролировать выполнение Правила Одного Определения (ODR, One Definition Rule) во время компоновки, и поэтому, чтобы компоновка прошла успешно, он допускает отступление от этого правила, которым Вы и воспользовались.

gzh
()

насколько я понимаю, когда С++ задумывался, то для этого как раз должно было использоваться ключевое слово export. Но на него забили и делают так как сейчас все делают, т.е. инклюдят шаблоны везде где они нужны, а линкер устраняет дубликаты.

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

Только для этого пришлось специально "чинить" линкер. Традиционный сишный линкер такого не умел.

svu ★★★★★
()
Ответ на: комментарий от svu

Спасибо за разъяснения.

Не скажу, что идея с шаблонами плоха, более того, иногда даже очень помогает, но вот метод ее реализации говорит о том, что в С++ костыль на костыле сидит и костылем погоняет (при всем моем уважении к труду Страуструпа).

Alexey-ZAR
() автор топика
Ответ на: комментарий от Alexey-ZAR

> метод ее реализации говорит о том, что в С++ костыль на костыле сидит и костылем погоняет

А что вы могли бы предложить?

Legioner ★★★★★
()
Ответ на: комментарий от Alexey-ZAR

Реализовать "экспорты" (это как раз когда объявление параметризованного класса можно поместить в заголовок, определение - в отдельно и однократно транслируемый cpp-файл) оказалось непомерно сложной задачей. Насколько мне известно, единственный компилятор, который ее решает - это Comeau C++. Это не говорит о том, что С++ - плохой или какой-то непоследовательный язык. Он достаточно целостный, особенно для своего возраста, и в самом языке особых "костылей" нет.

gzh
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.