views:

534

answers:

4

Why are default template arguments only allowed on class templates? Why can't we define a default type in a member function template? For example:

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

Instead, C++ forces that default template arguments are only allowed on a class template.

A: 

Because there is no sense declare default. Instantiation of function concerned with specifying explicit parameter, so:

 int a;
 mymember<int>(a);

is ALREADY absolute equivalent to:

 int a;
 mymember(a);
Dewfy
+15  A: 

It makes sense to give default template arguments. For example you could create a sort function:

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

C++0x introduces them to C++. See this defect report by Bjarne Stroustrup: Default Template Arguments for Function Templates and what he says

The prohibition of default template arguments for function templates is a misbegotten remnant of the time where freestanding functions were treated as second class citizens and required all template arguments to be deduced from the function arguments rather than specified.

The restriction seriously cramps programming style by unnecessarily making freestanding functions different from member functions, thus making it harder to write STL-style code.

Johannes Schaub - litb
Are there some link with that information?
Arman
@Arman, the defect report link contains the changes that are made to the working draft for C++0x and the discussions. Arguments neither deduced nor explicitly specified are obtained from default arguments. GCC4.4 supports default arguments for function templates in C++0x mode.
Johannes Schaub - litb
Nothing to do with the question or answer, but Herb Sutter called the upcomming standard C++11 after last saturdays meeting. I just read it today and feel like sharing :) http://herbsutter.wordpress.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/
David Rodríguez - dribeas
+6  A: 

To quote C++ Templates: The Complete Guide (page 207):

When templates were originally added to the C++ language, explicit function template arguments were not a valid construct. Function template arguments always had to be deducible from the call expression. As a result, there seemed to be no compelling reason to allow default function template arguments because the default would always be overridden by the deduced value.

James McNellis
+2  A: 

So far, all the proffered examples of default template parameters for function templates can be done with overloads.

AraK:

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

could be:

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

My own:

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

could be:

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())

could be:

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())

Stroustrup:

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

Could be:

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

Which I proved with the following code:

#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)
}

The printed output matches the comments for each call to f, and the commented-out call fails to compile as expected.

So I suspect that default template parameters "aren't needed", but probably only in the same sense that default function arguments "aren't needed". As Stroustrup's defect report indicates, the addition of non-deduced parameters was too late for anyone to realise and/or really appreciate that it made defaults useful. So the current situation is in effect based on a version of function templates which was never standard.

Steve Jessop
@Steve: So the egg was running faster than chicken?:) interesting. Thanks.
Arman
Probably just one of those things. The C++ standardisation process runs slow in part so that people have time to realise when a change creates opportunities or difficulties elsewhere in the standard. Difficulties hopefully are caught by the people implementing the draft standard as they go along, when they spot a contradiction or ambiguity. Opportunities to allow things that weren't allowed before, rely on someone who wants to write the code noticing that it no longer needs to be illegal...
Steve Jessop