函数模板的默认模板参数

为什么仅在类模板上允许默认的模板参数? 为什么我们不能在成员函数模板中定义一个默认types? 例如:

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

相反,C ++强制默认模板参数只能在类模板上使用。

给予默认模板参数是有道理的。 例如你可以创build一个sorting函数:

 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 ++中。 请参阅Bjarne Stroustrup的缺陷报告: function模板的默认模板参数以及他所说的内容

对函数模板的默认模板参数的禁止是独立函数被视为二等公民的时间的一个不合时宜的残余,并且需要从函数参数中推导出所有的模板参数而不是指定的。

这个限制严重地使编程风格受到不必要的限制,使独立函数不同于成员函数,从而使得编写STL风格的代码更加困难。

引用C ++模板:完整指南 (第207页):

当模板最初添加到C ++语言时,显式函数模板参数不是有效的构造。 函数模板参数总是必须从调用expression式中推导出来。 因此,似乎没有强制性的理由来允许默认的函数模板参数,因为默认值总是被推导的值所覆盖。

到目前为止,所有提供的函数模板默认模板参数的例子都可以通过重载来完成。

阿拉克:

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

我用下面的代码certificate了这一点:

 #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的每个调用的注释相匹配,并且注释掉的调用不能按预期进行编译。

所以我怀疑默认的模板参数“不需要”,但可能只是在默认的函数参数“不需要”的意义上。 正如Stroustrup的缺陷报告指出的那样,添加非推导参数对于任何人来说都意识不到和/或真正意识到它使默认值有用是太迟了。 所以目前的情况是基于一个从来没有标准的function模板的版本。

在Windows上,使用Visual Studio的所有版本,可以将此错误( C4519 )转换为警告或禁用它,如下所示:

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

在这里看到更多细节。

我使用的是下一个技巧:

可以说你想要这样的function:

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

我们可以看到没有必要明确设置第二个参数。 也许这对某个人有用。