Почему шаблонные функции не отображаются в LLVM-IR?

Почему шаблонные функции не отображаются в LLVM-IR, если функция не вызывается при генерации LLVM IR из кода C++, в отличие от других типов функций (int, float...), которые будут присутствовать в примере llvm ir: следующая функция func1 не отображается в llvm ir

template <class tmp>
tmp func1 () {
    // ...
}

Но эта функция func2 всегда отображается в llvm ir

int func2 () {
    // ...
}

person Yasser Nezzari    schedule 03.02.2017    source источник
comment
Это не функция шаблона. Это шаблон функции. Это не функция, а план будущей функции. Это совершенно неважно. func<int> будет функция шаблона, то есть шаблон функции со всеми уже известными параметрами шаблона. Это создает экземпляр шаблона, заставляя его материализоваться.   -  person AnT    schedule 03.02.2017


Ответы (2)


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

template<typename T>
T foo() { /* ... */ }

Это не будет выводить никакого кода.

Но это с другой стороны:

template<typename T>
T foo() { /* ... */ }

int test() {
    return foo<int>();
}

Выведет код как для test, так и для foo<int>.

Вы также можете вручную создать экземпляр шаблона следующим образом:

template int foo<int>();
person Guillaume Racicot    schedule 03.02.2017

Это связано с тем, как работают шаблоны C++. Поскольку компилятор не знает, что такое tmp, пока вы не вызовете функцию (или, точнее, когда вы не создадите ее экземпляр), он не знает, как написать для нее код. Например, рассмотрим этот шаблон:

template <typename T>
T add(T left, T right) {
    return left + right;
}

Если T является целым числом, то тело функции представляет собой целочисленное сложение. Если T является двойным, это сложение с плавающей запятой. Если T является std::string, это вызов функции std::string::operator+.

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


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

template <typename T>
class Adder {
    T add(T left, T right) {
        return left + right;
    }
};

Adder<int> a;

это все еще не будет создавать экземпляр Adder<int>::add, даже если у компилятора есть вся информация, чтобы знать, что add<int> потенциально интересен, потому что вы фактически не вызываете или иным образом не создаете его экземпляр.

person Daniel H    schedule 03.02.2017