Аргументы шаблона по умолчанию для шаблонов функций - PullRequest
182 голосов
/ 15 марта 2010

Почему аргументы шаблона по умолчанию разрешены только в шаблонах классов? Почему мы не можем определить тип по умолчанию в шаблоне функции-члена? Например:

struct mycclass {
  template<class T=int>
  void mymember(T* vec) {
    // ...
  }
};

Вместо этого C ++ принудительно разрешает использовать аргументы шаблона по умолчанию только для шаблона класса.

Ответы [ 5 ]

145 голосов
/ 15 марта 2010

Имеет смысл задавать аргументы шаблона по умолчанию. Например, вы можете создать функцию сортировки:

template<typename Iterator, 
         typename Comp = std::less<
            typename std::iterator_traits<Iterator>::value_type> >
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
  ...
}

C ++ 0x вводит их в C ++. См. Этот отчет о дефектах Бьярна Страуструпа: Аргументы шаблонов по умолчанию для шаблонов функций и что он говорит

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

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

34 голосов
/ 15 марта 2010

Цитировать Шаблоны C ++: Полное руководство (стр. 207):

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

17 голосов
/ 15 марта 2010

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

арак:

struct S { 
    template <class R = int> R get_me_R() { return R(); } 
};

может быть:

struct S {
    template <class R> R get_me_R() { return R(); } 
    int get_me_R() { return int(); }
};

Мой собственный:

template <int N = 1> int &increment(int &i) { i += N; return i; }

может быть:

template <int N> int &increment(int &i) { i += N; return i; }
int &increment(int &i) { return increment<1>(i); }

LITB:

template<typename Iterator, typename Comp = std::less<Iterator> >
void sort(Iterator beg, Iterator end, Comp c = Comp())

может быть:

template<typename Iterator>
void sort(Iterator beg, Iterator end, std::less<Iterator> c = std::less<Iterator>())

template<typename Iterator, typename Comp >
void sort(Iterator beg, Iterator end, Comp c = Comp())

Страуструп:

template <class T, class U = double>
void f(T t = 0, U u = 0);

Может быть:

template <typename S, typename T> void f(S s = 0, T t = 0);
template <typename S> void f(S s = 0, double t = 0);

Что я доказал с помощью следующего кода:

#include <iostream>
#include <string>
#include <sstream>
#include <ctype.h>

template <typename T> T prettify(T t) { return t; }
std::string prettify(char c) { 
    std::stringstream ss;
    if (isprint((unsigned char)c)) {
        ss << "'" << c << "'";
    } else {
        ss << (int)c;
    }
    return ss.str();
}

template <typename S, typename T> void g(S s, T t){
    std::cout << "f<" << typeid(S).name() << "," << typeid(T).name()
        << ">(" << s << "," << prettify(t) << ")\n";
}


template <typename S, typename T> void f(S s = 0, T t = 0){
    g<S,T>(s,t);
}

template <typename S> void f(S s = 0, double t = 0) {
    g<S,double>(s, t);
}

int main() {
        f(1, 'c');         // f<int,char>(1,'c')
        f(1);              // f<int,double>(1,0)
//        f();               // error: T cannot be deduced
        f<int>();          // f<int,double>(0,0)
        f<int,char>();     // f<int,char>(0,0)
}

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

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

4 голосов
/ 09 июля 2013

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

#ifdef  _MSC_VER
#pragma warning(1 : 4519) // convert error C4519 to warning
// #pragma warning(disable : 4519) // disable error C4519
#endif

Подробнее здесь .

1 голос
/ 23 июля 2011

Я использую следующий трюк:

Допустим, вы хотите иметь такую ​​функцию:

template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array)
{
    E one(1);
    array.add( one );
}

Вам не разрешат, но я поступлю следующим образом:

template <typename T>
struct MyArray_t {
void add(T i) 
{
    // ...
}
};

template <typename E, typename ARR_E = MyArray_t<E> >
class worker {
public:
    /*static - as you wish */ ARR_E* parr_;
    void doStuff(); /* do not make this one static also, MSVC complains */
};

template <typename E, typename ARR_E>
void worker<E, ARR_E>::doStuff()
{
    E one(1);
    parr_->add( one );
}

Таким образом, вы можете использовать это так:

MyArray_t<int> my_array;
worker<int> w;
w.parr_ = &arr;
w.doStuff();

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

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