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

Что такое полиморфизм времени компиляции и почему он применяется только к функциям?

Что такое полиморфизм времени компиляции и почему он применяется только к функциям?

4b9b3361

Ответ 1

Возвращение назад, когда "полиморфизм времени компиляции" означает перегрузку функции. Он применяется только к функциям, потому что они все, что вы можете перегрузить.

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

#include <iostream>
#include <string>

template <class T>
struct my_template { 
    T foo;
    my_template() : foo(T()) {}
};

template <>
struct my_template<int> {
    enum { foo = 42 };
};

int main() { 
    my_template<int> x;
    my_template<long> y;
    my_template<std::string> z;
    std::cout << x.foo << "\n";
    std::cout << y.foo << "\n";
    std::cout << "\"" << z.foo << "\"";
    return 0;
}

Это должно дать 42, 0 и "" (пустая строка) - мы получаем структуру, которая действует по-разному для каждого типа.

Здесь мы имеем "компиляционный полиморфизм времени" классов вместо функций. Я полагаю, что если вы хотите аргументировать этот момент, вы можете утверждать, что это хотя бы частично результат конструктора (функции) хотя бы в одном случае, но в специализированной версии my_template даже нет конструктора.

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

int value(int x) { return 0; }
long value(long x) { return 42; }

std::cout << value(1);
std::cout << value(1L);

Функциональная перегрузка и специализация дают аналогичные эффекты. Я согласен с тем, что он открывает какой-то вопрос о том, применим ли "полиморфизм" к одному из них, но я думаю, что он применим примерно одинаково к другому, как к другому.

Ответ 2

С полиморфизмом времени компиляции обычно подразумевается тот факт, что вы можете иметь несколько функций с тем же именем, и компилятор будет выбирать во время компиляции, которое можно использовать в зависимости от аргументов:

void foo(int x);
void foo(float y);

//Somewhere else
int x = 3;
foo(x); //Will call first function
float y = 2;
foo(y); //Will call second function

Функция foo называется перегруженной. Различные типы экземпляров шаблона также можно назвать полиморфизмом времени компиляции.

Ответ 3

Полиморфизм времени компиляции - это термин, который относится к программированию шаблонов С++. Например, во время компиляции вы определяете фактический тип std::vector тем, что он содержит:

std::vector <int> vi;
std::vector <std::string> vs;

Я не уверен, почему вы думаете, что он ограничен функциями.

Ответ 4

Вещь, которая применяется только к функциям, является вычитанием параметра шаблона. Если у меня есть шаблон функции:

template <typename T> 
void foo(T &t);

Тогда я могу сделать int a = 0; foo(a);, и это будет эквивалентно int a = 0; foo<int>(a);. Компилятор работает, я имею в виду foo<int>. По крайней мере, выясняется, что он должен использовать foo<int> - если это не то, что я имел в виду, тогда мне не повезло, и я мог написать foo<unsigned int>(a); или что-то еще.

Однако, если у меня есть шаблон класса:

template <typename T>
struct Foo {
    T &t;
    Foo(T &t) : t(t) {}
    T &getT() { return t; }
};

Тогда я не могу сделать int a = 0; Foo(a).getT();. Я должен указать Foo<int>(a). Компилятору не разрешено работать, я имею в виду foo<int>.

Итак, вы можете сказать, что шаблоны классов "менее полиморфны", чем шаблоны функций. Полиморфизм обычно означает, что вам не нужно писать код, чтобы сделать тип вашего объекта явным. Шаблоны функций позволяют это (в данном конкретном случае), а шаблоны классов - нет.

Что касается того, почему это так - стандарт говорит так, я не знаю, почему. Обычные подозреваемые: (а) это слишком сложно реализовать, (б) это не полезно, по мнению стандартного комитета, или (в) оно создает некоторое противоречие или двусмысленность в другом месте на языке.

Но вы все равно можете делать другие виды полиморфизма с классами:

template <typename T>
struct Foo {
    T &t;
    Foo(T &t): t(t) {}
    void handleMany(int *ra, size_t s) {
        for (size_t i = 0; i < s; ++i) {
            t.handleOne(ra[i]);
        }
    }
};

Это обычно называют полиморфизмом времени компиляции, поскольку в отношении автора шаблона t.handleOne может быть что угодно, и что он будет разрешен, когда это необходимо, "позже" в компиляции, когда Foo экземпляр.