1

我正在解决 Accelerate 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;
        }   
    }
}

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

没有匹配函数调用 reverse(std::vector::iterator,std::vector::iterator)'

比我变成这个

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

它起作用了,但我仍然不明白为什么第二个不起作用?

4

2 回答 2

2

编译器无法推断X代码中的内容。但是不需要为迭代器中包含的数据类型指定额外的模板类型。std::iterator包含一个 typedef,命名value_type它服务于这个确切的目的:

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;
        }   
    }
}
于 2012-04-22T15:47:51.277 回答
1

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

因为类型X实际上确实取决于传递给函数的迭代器类型,所以您可以使用value_typetype from iterator_traits。但是,这样做将要求用户对您的函数使用高级迭代器,reverse您也不想这样做。

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

此外,您的代码正在执行对象的不必要副本以将其移入和移出临时变量。这可能不适用于没有复制运算符(或复制构造函数)的高级对象。在 C++11 中,同样存在右值引用和移动语义。但即便如此 - 可能没有默认构造函数,因此您的代码会中断。

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

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

所以你最好使用swap:)

于 2012-04-22T15:55:53.790 回答