函数模板的默认模板参数

时间:2022-03-31 11:00:45

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++强制默认模板参数只能在类模板上使用。

5 个解决方案

#1


141  

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 Templates and 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样式的代码变得更加困难。

#2


34  

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++语言时,显式函数模板参数不是有效的构造。函数模板参数必须与调用表达式可约。因此,似乎没有令人信服的理由允许默认函数模板参数,因为默认值总是被推断值覆盖。

#3


16  

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:

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的缺陷报告所指出的那样,对于任何人来说,添加非推导的参数都太晚了,以至于没有人意识到或者真正理解它使默认值变得有用。因此,当前的情况实际上是基于函数模板的一个版本,而这个版本从来都不是标准的。

#4


4  

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.

看到更多的细节。

#5


1  

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.

我们可以看到,不需要显式地设置第二个参数。也许对某人有用。

#1


141  

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 Templates and 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样式的代码变得更加困难。

#2


34  

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++语言时,显式函数模板参数不是有效的构造。函数模板参数必须与调用表达式可约。因此,似乎没有令人信服的理由允许默认函数模板参数,因为默认值总是被推断值覆盖。

#3


16  

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:

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的缺陷报告所指出的那样,对于任何人来说,添加非推导的参数都太晚了,以至于没有人意识到或者真正理解它使默认值变得有用。因此,当前的情况实际上是基于函数模板的一个版本,而这个版本从来都不是标准的。

#4


4  

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.

看到更多的细节。

#5


1  

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.

我们可以看到,不需要显式地设置第二个参数。也许对某人有用。