Подтвердить что ты не робот

С++ 11: Явное объявление экземпляра против явного определения экземпляра

В чем разница между С++ 03 явного определения шаблона экземпляра и С++ 11 явного шаблона декларации экземпляра?

Я имею в виду, почему определение экземпляра недостаточно для того, чтобы компилятор не генерировал реализацию для других типов? Что не так в следующем примере: представьте, что я разделил объявление и определение шаблона на два отдельных файла:

ах

#pragma once

template<typename T>
class A
{
public:
    A(T t);

private:
    T _t;
};

a.cpp

#include "A.h"

template<typename T>
A<T>::A(T t) : _t(t) {}

template class A<int>; // explicit instantiation

main.cpp

#include "A.h"

int main()
{
    A<int> a(5); // fine, compiler generates header file,
                 // linker links with implementation from A.cpp file

    // A<float> b(3.14f); // linker error, as expected
}

Есть ли издержки времени компиляции в приведенном выше примере? Если я правильно понимаю, в таком случае, используя явное определение экземпляра в отдельном файле *.cpp (вместе с реализацией шаблона), я делаю компилятор неспособным неявно создавать экземпляр шаблона с любыми другими типами. Как таковой, почему существует отдельный синтаксис для явного объявления экземпляра?

Как явное объявление экземпляра может ускорить время компиляции, если я УЖЕ скрыл реализацию в файле A.cpp, используя явное определение экземпляра, и запретил компилятору генерировать тело для других типов. Связано ли "явное объявление экземпляра" с "явным определением экземпляра", я имею в виду, следует ли использовать их оба, или это совершенно отдельные функции (например, явное объявление экземпляра можно использовать только в том случае, если явное определение экземпляра не использовалось)?

Правильно ли я думаю, что явное определение экземпляра предназначено только для того, чтобы вызвать ошибку, если никакой другой модуль перевода не создает экземпляр шаблона с использованием данного типа?

4b9b3361

Ответ 1

Когда вы помещаете явное определение экземпляра в файл A.cpp, как компилятор должен знать его там при компиляции main.cpp? Ответ заключается в том, что он не может, поэтому он все равно будет создавать шаблоны, используемые в main.cpp, и в вашем случае использование явного определения экземпляра бесполезно и не помогает.

Объявление явного инстанцирования говорит компилятору: "Не утруждайте создание экземпляра этого шаблона, я сделаю это сам, где-то еще в программе", и определение - это то, что выполняет это обещание.

Явное инстанцирование должно быть определено ровно один раз только в одном файле, но оно может быть объявлено несколько раз в разных файлах. Это ничего не уникально для шаблонов, в C и С++ те же правила применяются к (не встроенным) функциям: вы можете объявлять их несколько раз в разных файлах (обычно, помещая объявление в заголовок), а затем вы должны точно определить функцию один раз, в одном файле.

Итак, чтобы ваш пример работал правильно, вы должны добавить объявление в A.h:

extern template class A<int>; // explicit instantiation declaration

Ответ 2

Явное объявление создания экземпляра (внешний шаблон) пропускает шаг неявного создания экземпляра: код, который в противном случае вызвал бы неявное создание экземпляра, вместо этого использует явное определение создания экземпляра, предоставленное в другом месте (что приводит к ошибкам связи, если такого создания не существует). Это можно использовать для сокращения времени компиляции, явно объявив создание экземпляра шаблона во всех, кроме одного из исходных файлов, используя его, и явно определив его в оставшемся файле. Источник

Здесь объявление в main.cpp или Ah не позволило бы main.cpp генерировать (во время компиляции) код, основанный на том, какие части шаблона видны, а именно специализация Ah -based A<int>:

class A<int>
{
public:
    A(int t);
private:
    int _t;
};

Однако код main.cpp должен знать, что A<int>::A(int) существует, что означает, что он должен выполнять своего рода инстанцирование для изучения всех членов A<int>, что в точности соответствует Ah [CN00 ] A<int> экземпляр будет делать.

Так что, да, не совсем очевидно, как это полезно здесь - хотя при условии профилирования для каждого компилятора/платформы.