通用函数中的模板参数

时间:2012-04-22 15:37:24

标签: c++ templates

我正在解决加速c ++的运动问题,这是

  

实现我们在§8.2.5/ 148中使用的交换函数。我们为什么这样做   调用swap而不是直接交换* beg和* end的值?   提示:试一试,看看。

书中的实际功能是

template<class Bi> void reverse(Bi begin, Bi end) {
while (begin != end) {
       --end;
        if (begin != end)
           swap(*begin++, *end);
     } }

我改成了这个

template<class Bi,class X> 
void reverse(Bi b, Bi e)
{
    X tmp;
    while (b!= e) {
        --e;
        if (b != e)
        {
           tmp=*b;
           *b=*a;
           *a=tmp;
            --b;
        }   
    }
}

它没有用,给出了以下错误。

  

没有匹配的呼叫功能   反向(标准::向量:迭代,性病::矢量:迭代)'

比我变成了这个

template<class Bi,class X> 
void reverse(Bi b, Bi e,X c)
{
    X tmp=c;
    while (b!= e) {
        --e;
        if (b != e)
        {
           tmp=*b;
           *b=*a;
           *a=tmp;
            --b;
        }   
    }
}

并将上述功能称为

reverse(v.begin(),v.end(),0);

它有效,但我仍然没有弄清楚为什么第二个不工作?

2 个答案:

答案 0 :(得分:2)

编译器无法推断代码中的X。但是没有必要为迭代器中包含的数据类型指定额外的模板类型。 std::iterator包含一个名为value_type的typedef,用于实现这个目的:

template<class Bi> 
void reverse(Bi b, Bi e)
{
    typename Bi::value_type tmp;
    while (b!= e) {
        --e;
        if (b != e)
        {
           tmp=*b;
           *b=*a;
           *a=tmp;
            --b;
        }   
    }
}

答案 1 :(得分:1)

您的问题在于新引入的模板参数X,编译器无法确定该参数,因为它不依赖于参数。因此,reverse的呼叫者必须指定它。它们显然没有,因此编译器拒绝代码。

因为类型X实际上依赖于传递给函数的迭代器类型,所以您可以使用iterator_traits中的value_type类型。但是,这样做需要用户使用具有reverse功能的高级迭代器,您不想这样做。

C ++ 11有decltype来解决类似的问题。但是您可能不希望代码依赖于全新的功能,因为许多编译器不支持它。

此外,您的代码正在执行对象的不必要副本,以将其移入和移出临时变量。对于没有复制操作符(或复制构造函数)的高级对象,这可能不起作用。在C ++ 11中,还有rvalue引用和移动语义。但即便如此 - 可能没有默认的构造函数,所以你的代码会破坏。

理论上,您可以使用类型特征来确定传递给reverse的对象的类型,并使用模板特化来提出不同的实现,但实际上...... swap正在使用函数重载所以类型可以自动确定,它支持C ++ 11等的移动语义。如果没有内联,使用它会是一个问题,例如,为每个元素推送/弹出框架。但事实并非如此。

此外,swap可以自己专门化。例如,对于POD类型,它可以使用XOR来交换两个元素的内容,而无需创建额外的副本。现代编译器无论如何都会为你做这件事,但只是一个想法......

所以你最好使用swap:)