VS2013:将迭代器传递给一个带指针的函数(将VS2010迁移到VS2013)

时间:2014-04-29 09:54:46

标签: c++ c++11

我有以下代码,当我在VS2010中编译它时,编译通过并且一切正常。

AA.h

class AA
{
    int i;
public:
    AA()
    {
        i = 0;
    }
    void setA(AA *a)
    {
        i = a->geti();
    }

    int geti()
    {
        return i;
    }
    void seti(int i)
    {
        this->i = i;
    }

};

Source.cpp

#include <vector>
#include <iostream>
#include "AA.h"
using namespace std;

int main()
{
    AA a1;
    AA a2;
    AA a3;
    a1.seti(1);
    a2.seti(2);
    a3.seti(3);
    vector<AA> aList;

aList.push_back(a1);
aList.push_back(a2);
aList.push_back(a3);

for (vector<AA>::iterator itr = aList.begin();
    itr != aList.end(); itr++)
{
    AA aa;
    aa.setA(itr); // Compiler error on VS2013
    cout << aa.geti();
}

return 0;
}

但是在VS2013中编译相同的代码会给我以下编译错误:

  

Source.cpp(52):错误C2664:'void AA :: setA(AA *)':无法转换   参数1来自   '的std :: _ Vector_iterator&GT;&GT;'至   'AA *'1&gt;没有可用的用户定义转换运算符   执行此转换,或者无法调用运算符

对此的简单直接修复将显式取消引用迭代器并传递给set函数,如下所示:

for (vector<AA>::iterator itr = aList.begin();
        itr != aList.end(); itr++)
    {
        AA aa;
        aa.setA(&*itr); // No error
        cout << aa.geti();
    }

但问题是我们在数千个源文件中有类似的代码,并且在所有文件中进行更改将非常耗时且实际上不可能。

有人可以告诉我,无论如何解决这个问题而不改变所有文件?我们可以在AA.h中做些什么来处理这个问题?

2 个答案:

答案 0 :(得分:4)

一种选择是为当前需要指针的代码使用模板:

template <typename Iterator>
void setA(Iterator a)
{
    i = a->geti();
}

唯一的缺点是,它会接受通过取消引用geti()调用->方法的任何内容,返回可以分配给int的内容有效。但是,您可以使用SFINAE将其限制为类AA

答案 1 :(得分:1)

template<typename T>
struct AsPointer {
  T* p;
  operator T*() const { return p; }
  T* operator->() const { return p; }
  T& operator*() const { return *p; }
  explicit operator bool() const { return p; }
  AsPointer():p(nullptr) {}
  AsPointer(AsPointer const&)=default;
  AsPointer(AsPointer&)=default;
  AsPointer(AsPointer const&&)=default;
  AsPointer(AsPointer&&)=default;
  // sfinae may not work here, but at least you get an error:
  template<typename U,typename=typename std::iterator_traits<typename std::decay<U>::type>::iterator_category>
  AsPointer(U&& u):p(&*u) {}
  template<typename U>
  AsPointer(U* u):p(u) {}
  AsPointer(std::nullptr_t):p(nullptr) {}
};

是一个template伪指针,可以像指针一样对待,但也可以从任何iterator隐式转换。当您发现错误时,可以将界面中的foo*替换为AsPointer<foo>,并希望事情顺利进行。

如果您将NULL传递给上述AsPointer,则可能会抱怨 - 将其更改为nullptr。但除此之外,它可以通过一个界面更改来解决所有呼叫站点问题。

我,我只是扫过呼叫网站。

请注意,const int*变为AsPointer<const int>而不是const AsPointer<int>