模板中的隐式const转换

时间:2011-11-10 05:15:33

标签: c++ const-cast

我遇到类似于以下代码片段的内容,这会引发编译器错误,因为它使用了const_iteratorvec.end()中的std::copy是否有理由不隐式获得const演员?

int main(int argc, char* argv[]) {

    vector<int> vec;
    vec.push_back(20);
    vec.push_back(30);
    vector<int> copy_vec;
    vector<int>::const_iterator i = vec.begin();
    std::copy(i,vec.end(),back_inserter(copy_vec));
    cerr<<copy_vec.size()<<endl;
    return 0;
}

3 个答案:

答案 0 :(得分:5)

不需要std::copy,也不需要一对迭代器。

这样做:

vector<int> copy_vec(vec); //use the copy constructor!

你已经完成了!

至于你的代码给出错误的原因,是因为std::copy的第一个迭代器是const_iterator,而第二个迭代器只是iterator。两者都必须是相同的类型,但它们不是,并且因此,std::copy的模板参数推导失败,这是一个函数模板。

要通过示例来理解这一点,请考虑以下简单代码:

template<typename T>
void f(T a, T b) {}

int main()
{
    int a = 100;
    char b = 'A';
    f(a,b);
}

提供错误(请参阅ideone):

prog.cpp:8: error: no matching function for call to ‘f(int&, char&)’

它不会编译,因为我们依赖于模板参数推断。由于函数模板中第一个参数和第二个参数的类型完全相同,但我们称这个函数将aint)作为第一个参数传递给{{{ 1}}(即b)作为第二个参数,它不能从不同类型的参数中唯一地推导出char请注意,在模板参数扣除期间不会考虑转换。

但是,如果我们不依赖于模板参数推导,而是明确地提供模板参数,那么它将起作用(参见ideone):

T

它起作用,因为不需要从函数参数中推导出f<int>(a,b); //works!

同样,如果您为T提供模板参数,那么即使您的代码也可以使用(请参阅ideone):

std::copy

它有效,因为std::copy<vector<int>::const_iterator>(i,vec.end(),back_inserter(copy_vec)); //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicitly provide template argument! 可以转换为iterator,但const_iterator无法转换为const_iterator,这意味着以下内容会产生错误(请参阅ideone):

iterator

答案 1 :(得分:1)

vec是一个非const向量,因此end将返回一个非const迭代器。这样的迭代器实际上不能隐式转换为const版本,因为它们是单独的类。

而是使用两个迭代器构造函数:

vector<int> copy_vec(vec.begin(), vec.end());

答案 2 :(得分:0)

我认为这里的问题是声明std :: copy采用三个参数。

前两个是相同的类型,并且您正在传递( const_iterator, vec.end () ) - 并且vec.end()返回一个非const迭代器(因为vec是一个非const向量)。这会导致编译器拒绝std :: copy的模板。

如果你有这样的功能:

void doit ( const std::vector<int> &vec, std::vector<int> &out ) {
    std::vector<int>::const_iterator i = vec.begin();
    std::copy(i,vec.end(),back_inserter(out));
    }

然后它将编译并正常工作,因为vec.end()将返回一个const_iterator。 或者,如果您使用的是C ++ 11,则可以调用vec.cend()来获取const_iterator。