函数模板的默认模板参数

Arm*_*man 183 c++ templates

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

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

相反,C++强制只允许在类模板上使用默认模板参数.

Joh*_*itb 146

给出默认模板参数是有意义的.例如,您可以创建一个排序函数:

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

C++ 0x将它们引入C++.请参阅Bjarne Stroustrup的此缺陷报告:功能模板的默认模板参数以及他所说的内容

禁止函数模板的默认模板参数是一个错误的剩余时间,其中独立功能被视为二等公民,并要求所有模板参数从函数参数推断而不是指定.

这种限制通过不必要地使独立函数与成员函数不同而严重地限制了编程风格,从而使得编写STL样式代码变得更加困难.

  • 与问题或答案无关,但Herb Sutter在上周六会议结束后称之为升级标准C++ 11.我今天刚看完它,感觉就像分享一样:) http://herbsutter.wordpress.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ (4认同)

Jam*_*lis 35

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

当模板最初添加到C++语言时,显式函数模板参数不是有效的构造.函数模板参数总是必须从调用表达式中推导出来.因此,似乎没有令人信服的理由允许默认函数模板参数,因为默认值总是会被​​推导出的值覆盖.


Ste*_*sop 17

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

阿拉克:

struct S { 
    template <class R = int> R get_me_R() { return R(); } 
};
Run Code Online (Sandbox Code Playgroud)

可能:

struct S {
    template <class R> R get_me_R() { return R(); } 
    int get_me_R() { return int(); }
};
Run Code Online (Sandbox Code Playgroud)

我自己的:

template <int N = 1> int &increment(int &i) { i += N; return i; }
Run Code Online (Sandbox Code Playgroud)

可能:

template <int N> int &increment(int &i) { i += N; return i; }
int &increment(int &i) { return increment<1>(i); }
Run Code Online (Sandbox Code Playgroud)

litb:

template<typename Iterator, typename Comp = std::less<Iterator> >
void sort(Iterator beg, Iterator end, Comp c = Comp())
Run Code Online (Sandbox Code Playgroud)

可能:

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())
Run Code Online (Sandbox Code Playgroud)

斯特劳斯:

template <class T, class U = double>
void f(T t = 0, U u = 0);
Run Code Online (Sandbox Code Playgroud)

可能:

template <typename S, typename T> void f(S s = 0, T t = 0);
template <typename S> void f(S s = 0, double t = 0);
Run Code Online (Sandbox Code Playgroud)

我用以下代码证明了这一点:

#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)
}
Run Code Online (Sandbox Code Playgroud)

打印输出与每次调用f的注释匹配,注释掉的调用无法按预期编译.

所以我怀疑默认模板参数"不需要",但可能只是在默认函数参数"不需要"的情况下.正如Stroustrup的缺陷报告所指出的那样,添加非推断参数为时已晚,任何人都无法实现和/或真正意识到它使默认值有用.因此,目前的情况基于一个从未标准的功能模板版本.

  • 还有一件事:`template <typename T = void> int SomeFunction();`.这里的模板参数从未使用过,实际上函数永远不会被调用; 它被引用的唯一地方是`decltype`或`sizeof`.该名称故意匹配另一个函数的名称,但事实上它是一个模板意味着编译器将更喜欢自由函数(如果存在).这两个在SFINAE中用于提供缺少函数定义的默认行为. (2认同)