Значение слова «экземпляр» в отношении шаблонов - PullRequest
6 голосов
/ 05 сентября 2011

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

Приведенная выше цитата из книги: Шаблоны C ++ Аддисона Уэсли .

Я хочу понять значение жаргона " код создан ". Означает ли это, что зарезервирована только определенная память, или только этот код скомпилирован или что-то еще?

Ответы [ 5 ]

7 голосов
/ 05 сентября 2011

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

Шаблоны не напрямую скомпилированы в любой объект, который позже.используется с другими аргументами (что верно в обобщениях C #, но не в C ++), но скорее код анализируется компилятором и сохраняется в памяти на случай, если он будет позже использован при обработке текущего модуля перевода.То есть компилятор обрабатывает шаблон ( шаблон курсивом используется в английской форме шаблона, из которого создаются вещи, а не точное значение C ++), из которого он будет созданкод (классы или функции) при необходимости. Instantiation - это процесс, с помощью которого компилятор определяет, что конкретный шаблон используется с определенным набором аргументов, и выполняет подстановку аргументов в шаблоне для генерации класса или функции для компиляции и окончательной компиляции в двоичный код шаблона.

Существует два типа реализации шаблона: неявный и явный и цитата, на которую вы ссылаетесь, о неявных шаблонах .Я начну с явной реализации шаблона только потому, что он проще.Когда вы явно создаете экземпляр шаблона (Google для синтаксиса), вы сообщаете компилятору, что вы хотите, чтобы код, сгенерированный из этого шаблона , применялся к конкретным аргументам, которые вы предоставляете.В случае class-template это вызывает создание экземпляров всех функций-членов, что в основном означает, что компилятор подставит типы и скомпилирует результат этого в двоичные объекты.

Неявная реализация , с другой стороны, выполняется по требованию.Когда вы используете шаблон класса, биты и кусочки, которые на самом деле используются , генерируются из шаблона и компилируются в модуль перевода.Если вы создаете определение переменной std::vector<int> v;, компилятор применяет тип int (и тип по умолчанию std::allocator<int>) к template std::vector и создает тип std::vector<int>, но при этом он не компилируетсявсе функции-члены, но только те, которые необходимы, что в данном случае будет конструктором по умолчанию std::vector<int>::vector() и деструктором std::vector<int>::~vector().Остальные методы не компилируются, и для них не будет кода в двоичном виде.

Есть несколько причин, по которым не создаются не все функции-члены, и причиныварьируются по сложности от простых до глубоких языковых деталей.Для некоторых из более простых вы можете рассмотреть производительность компиляции (отсутствие необходимости генерировать / компилировать все функции-члены только потому, что используется одна из них, значительно сократит время компиляции).Немного более сложным является тот факт, что различные функции-члены в шаблоне могут предъявлять разные требования к типу экземпляра.Например, operator[] для map требует, чтобы тип значения был default-constructible , так как оператор создаст новый элемент, если он еще не существовал на карте, с другойстороны, если вы всегда используете find и insert, вы можете использовать std::map с типами, которые не могут быть использованы по умолчанию.Не заставляя компилировать все функции-члены, язык позволяет использовать шаблон с аргументами, которые не будут отвечать всем требованиям всех методов, если он действительно соответствует требованиям тех методов, которые на самом деле используется .

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

1 голос
/ 05 сентября 2011

Важным моментом является то, что метод шаблона в классе будет скомпилирован только в том случае, если его вызывает некоторый код.Это подразумевает, что шаблонный метод, который НЕ МОЖЕТ быть скомпилирован, не является проблемой, если никто не ссылается на него.

Подобно функции, которая будет генерировать ошибку времени выполнения, это не проблема, если она не вызывается,функция шаблона, которая будет генерировать ошибку компилятора при создании экземпляра, не является проблемой, если кто-то не создает ее.Например:

#include <stdio.h>
#include <string>

template<typename T>
struct Foo
{
    const T& x;

    Foo(const T& x) : x(x) {}

    template<typename S>
    operator S () const
    {
        S s;
        s = x + 1;
        return s;
    }
};

int main()
{
    std::string s = "bar";
    int i = 42;
    Foo<std::string> fs(s);
    Foo<int> fi(i);

    printf("Here we go... -> %f\n", double(fi));
    // printf("This won't compile -> %f\n", double(fs));
    return 0;
}

Этот код компилируется, даже если при создании экземпляра Foo<std::string> было бы недопустимо создавать неявное преобразование в double (потому что x+1 недопустимо с std::string).

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

0 голосов
/ 05 сентября 2011

Процесс замены параметров шаблона конкретными типами называется Создание экземпляра . Это приводит к экземпляру шаблона. компилятор генерирует код для шаблонной функции / класса с запрошенным типом .

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

Утверждение из книги объясняет это.

0 голосов
/ 05 сентября 2011

Да . «Код создается» означает, что код помещается в память (сегмент кода). Это происходит, только если конкретный метод / переменная указан в коде.

(Термин Ссылается не означает, что функция вызывается во время выполнения. Это означает, что метод присутствует где-то в вашем коде. Поэтому, если метод ссылается , тогда он будет быть скомпилирован и код для этого будет выпущен.)

Например,

template<typename T>
T add(T a, T b) { return a + b; }

Теперь, если в вашем коде есть ссылка для типа double as,

double d = add(2.3, 4.6);

тогда компилятор выдаст код только для add<double>(). Нет смысла выдавать код для add<int>() или add<A>().

0 голосов
/ 05 сентября 2011

Я полагаю, это относится к тому факту, что код шаблона, который не используется, никогда даже не просматривается компилятором. В результате вы можете, например, иметь синтаксические ошибки в шаблоне класса, которые не вызовут ошибок компиляции, если класс никогда не используется в вашем коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...