C++ 函数模板的默认模板参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2447458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:31:05  来源:igfitidea点击:

Default template arguments for function templates

c++templates

提问by Arman

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.

相反,C++ 强制默认模板参数只允许用于类模板。

采纳答案by Johannes Schaub - litb

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

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

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 introduces them to C++. See this defect report by Bjarne Stroustrup: Default Template Arguments for Function Templatesand what he says

C++0x 将它们介绍给 C++。请参阅 Bjarne Stroustrup 的这份缺陷报告:函数模板的默认模板参数以及他所说的

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.

禁止函数模板的默认模板参数是那个时代的错误残余,独立函数被视为二等公民并要求所有模板参数从函数参数中推导出而不是指定。

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

回答by James McNellis

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

引用C++ 模板:完整指南(第 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.

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

回答by Steve Jessop

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.

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

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.

所以我怀疑默认模板参数“不需要”,但可能只是与默认函数参数“不需要”相同。正如 Stroustrup 的缺陷报告所指出的那样,添加非推导参数对于任何人来说都太晚了,无法意识到和/或真正意识到它使默认值变得有用。因此,目前的情况实际上是基于从未标准的功能模板版本。

回答by Adi Shavit

On Windows, with all versions of Visual Studio you can convert this error (C4519) to a warning or disable it like so:

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

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

See more details here.

在此处查看更多详细信息。

回答by alariq

What I use is next trick:

我使用的是下一个技巧:

Lets say you want to have function like this:

假设你想要这样的功能:

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

You will not be allowed, but I do next way:

你不会被允许,但我做下一个方式:

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

So this way you may use it like this:

因此,您可以这样使用它:

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

As we can see no need to explicitly set second parameter. Maybe it will be useful for someone.

正如我们所见,无需显式设置第二个参数。也许它对某人有用。