Вызов функции шаблона без <>; вывод типа - PullRequest
10 голосов
/ 14 мая 2010

Если у меня есть шаблон функции с typename T, где компилятор может сам устанавливать тип, мне не нужно явно писать тип при вызове функции, например:

template < typename T > 
T min( T v1, T v2 ) {
   return ( v1 < v2 ) ? v1: v2;
}
int i1 = 1, i2 = 2; int i3 = min( i1, i2 ); //no explicit <type> 

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

template < typename TOut, typename TIn >
TOut round( TIn v ) {
   return (TOut)( v + 0.5 );
}
double d = 1.54;
int i = round<int>(d); //explicit <int>

Правда ли, что мне всегда нужно указывать хотя бы 1 имя типа? Я предполагаю, что причина в том, что C ++ не может различать функции между различными типами возвращаемых значений.

Но если я использую функцию void и передаю ссылку, опять же, я не должен явно указывать возвращаемое имя типа:

template < typename TOut, typename TIn > 
void round( TOut & vret, TIn vin ) {
   vret = (TOut)(vin + 0.5);
}
   double d = 1.54;
   int i; round(i, d); //no explicit <int>

Должен ли вывод заключаться в том, чтобы избегать функций с возвратом и отдавать предпочтение void функциям, которые возвращаются через ссылку при написании шаблонов? Или есть возможность избежать явного написания возвращаемого типа? Что-то вроде «вывода типа» для шаблонов. Возможно ли "определение типа" в C ++ 0x?

Ответы [ 3 ]

16 голосов
/ 14 мая 2010

Разрешение перегрузки выполняется только на основе аргументов функции; возвращаемое значение не используется вообще. Если тип возвращаемого значения не может быть определен на основе аргументов, вам придется указать его явно.

Я бы не пошел по пути «возврата» значения через опорный параметр; это делает вызывающий код неясным. Например, я бы предпочел это:

double x = round<double>(y);

за это:

double x;
round(x, y);

потому что в последнем случае легко спутать ввод и вывод, и совсем не ясно, что x изменяется.

В конкретном случае round вам, вероятно, понадобится только один или два типа для TOut, так что вы можете просто оставить этот аргумент шаблона вне:

template<typename TIn>
int roundToInt(TIn v) {
    return (int)(v + 0.5);
}

Я нахожу roundToInt(x) немного яснее, чем round<int>(x), потому что ясно, для чего используется тип int.

3 голосов
/ 14 мая 2010

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

Нет, почему? Что вы получаете? Только вывод типа (так меньше кода для записи). Но вы теряете гораздо более логичный синтаксис присвоения значения (и, следовательно, больше кода для записи). Итак, одно получено, другое потеряно. Я не вижу выгоды в целом.

Может даже помочь явно указать тип шаблона: рассмотрим случай lexical_cast. Не указывать тип возвращаемого шаблона может привести к путанице.

2 голосов
/ 14 мая 2010

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

vret = (TOut)(vin + 0.5);

против

vret = static_cast<TOut>(vin + 0.5);

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

...