2015-04-16 2 views
57
template< class T > 
class Foo { 
public: 
    Foo(T t) { } 
}; 

int main() { 
    int i = 0; 
    Foo f(i); 
} 

В приведенном выше коде компилятор жалуется, что аргументы шаблона отсутствуют до «f». Я понимаю, что вывод аргументов шаблона для класса из аргументов конструктору не является частью стандарта, но почему мой вопрос? Разве компилятор не имеет всей необходимой информации, чтобы неявно создать экземпляр Foo<int> и вызвать его конструктор?Почему конструкторы не могут выводить аргументы шаблона?

Отредактированный, чтобы понять, что я называю конструктор с int (в отличие от short, long, void* и т.д.)

+2

Не может 0 также представлять 'bool' или' char' или указатель? или это просто неявное преобразование? – mstbaum

+2

Что касается практической проблемы (а не почему), то с текущим C++ просто используйте заводскую функцию. –

+2

@mstbaum: Хотя верно, я не уверен, что это актуально, так как намерение явно состоит в том, чтобы следовать одному и тому же выводу аргумента шаблона как функции, где все это четко указано. –

ответ

34

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

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4471.html

Update: Вот новая версия предложения:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0091r0.html

+11

Это может быть хорошей идеей обобщить некоторые трудности из связанной статьи в самом ответе. Хотя это не совсем правильный ответ на ссылку, это потеряло бы значительную ценность, если бы ссылка умерла. – IMSoP

+1

@IMSoP Пока вы правы о включении информации, предложения C++ никуда не собираются в ближайшее время –

18

TL; DR: специализация шаблона


Они могут, но только шаблонные аргументы самой функции, а не типа.

Объявление Foo f(0); является незаконным, поскольку нет такого типа, как Foo. Возможно, вы думали о

auto f = Foo(0); 

но не допускается либо, потому что компилятор не знает, что возможности для поиска в (существует бесконечное количество возможных типов с конструктором по имени Foo и, по специальности, возможно, больше, чем один с конструктором Foo(int))

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

auto f = make_foo(0); 

где функция фабриканта тип возвращаемого значения зависит от типа удержания его р arameters.


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

8

Foo класс шаблон, а не класс. Его тип всегда должен быть каким-то образом поставлен для класса, который должен быть сгенерирован с правильными типами. Вы не можете сделать Foo, потому что Foo не тип, но Foo<int> есть. Это создает класс вроде этого:

class Foo { 
public: 
    Foo(int t) { } 
}; 

Если только вы предоставили Foo, компилятор не будет знать, как создать класс.Foo<int> f(0) работает, потому что Foo<int> генерирует класс, заменяя T на int. По типу, который вы вызываете конструктор, компилятор уже знает, что конструктор принимает int.

+1

Хорошо сделано, напоминая людям, что шаблон не является типом. (Я первоначально использовал «+1» вместо первых двух слов, но, видимо, это недопустимо) –

5

Название класса, который вы хотите создать, - Foo<int> (как вы укажете).

Также можно написать Foo<short> f(0), или Foo<unsigned long> f(0), или Foo<Foo<double>*> f(0). В этих случаях, однако, вы не ожидаете, что компилятор сможет угадать тип, если вы пишете только Foo f(0).

Можно себе представить, что C++ может были определены с правилами, чтобы сделать некоторые такие предположения определенным образом (например, буквальный 0 означает параметр типа int и никакой другой), но тогда язык будет даже больше сложнее, чем сейчас, и есть дополнительные способы для людей, чтобы сделать ошибки программирования. На самом деле писать то, что вы имеете в виду в объявлении, как это кажется не слишком много, чтобы спросить.

Edit: После размещения этого я заметил в другой ответ, что является предложение сделать такую ​​особенность C++, на самом деле, как можно было бы себе представить.

+0

Если я изменил экземпляр на 'int i = 0; Foo f (0); 'Компилятор должен иметь всю необходимую ему информацию, чтобы создать экземпляр' Foo 'и вызвать его contructor. Однако на основании вышеприведенных ответов я могу понять, почему компилятор попадает в 'Foo' и не знает, что с ним делать, и сразу сообщает об ошибке. –

+0

Извините, я имел в виду 'int i = 0; Foo f (i); '. И я согласен с тем, что было бы сложно реализовать, я просто хотел получить более полное представление о том, почему. –

+0

@wibs Спасибо за разъяснение, и я заменяю свой предыдущий комментарий соответственно. Идея вывести 'Foo f (0)' из 'Foo f (i)' или даже 'Foo f (0)' не является необоснованной (см. Предлагаемое изменение на языке, упомянутом в другом месте), и я даже могу быть убежден в конечном итоге, это хорошая идея. Пункт моего ответа на самом деле заключается в том, чтобы предложить, почему также было разумно, что он еще не добавлен в спецификацию языка. –

Смежные вопросы