【问题标题】:implicit const cast in templates模板中的隐式 const 强制转换
【发布时间】:2011-11-10 05:15:32
【问题描述】:

我遇到了类似于以下代码 sn-p 的内容,它会引发编译器错误,因为它使用了 const_iteratorstd::copy 中的 vec.end() 没有隐含地获得 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;
}

【问题讨论】:

    标签: c++ const-cast


    【解决方案1】:

    不需要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&)’
    

    它无法编译,因为我们依赖于模板参数推导。由于第一个参数和第二个参数的类型在函数模板中完全相同,但我们调用此函数传递a(即int)作为第一个参数和b(即char) 作为第二个参数,它不能从不同类型的参数中唯一地推断出T请注意,模板参数推导过程中不考虑转换。

    但是,如果我们不依赖模板参数推导,而是显式提供模板参数,那么它会起作用(参见ideone):

    f<int>(a,b);  //works!
    

    它的工作原理是不需要从函数参数中推断出T

    同样,如果您为std::copy 提供模板参数,那么即使您的代码也可以工作(参见ideone):

    std::copy<vector<int>::const_iterator>(i,vec.end(),back_inserter(copy_vec));
           //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicitly provide template argument!
    

    之所以有效,是因为iterator 可以转换为const_iterator,但const_iterator 不能转换为iterator,这意味着以下会出错(请参阅ideone):

    std::copy<vector<int>::iterator>(i,vec.end(),back_inserter(copy_vec));
            //^^^^^^^^^^^^^^^^^^^^^ non-const iterator!
    

    【讨论】:

    • 实际上上面只是一个示例代码,我更感兴趣的是弄清楚为什么不发生隐式 const 转换
    • @keety:我也解释了那部分。 :-)
    • @keety:模板函数的参数依赖查找(ADL)时没有类型转换。数据类型必须完全匹配。
    • @keety:我还添加了更多解释,用一个简单的例子!
    【解决方案2】:

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

    改为使用两个迭代器构造函数:

    vector&lt;int&gt; copy_vec(vec.begin(), vec.end());

    【讨论】:

    • 为什么不简单地vector&lt;int&gt; copy_vec(vec)? :P
    • 你错了>>Such an iterator actually cannot be implicitly converted to a const version, because they're separate classes.这不是它不起作用的原因(实际原因请参阅我的回答)。此外,非 const 迭代器可以隐式转换为 const 迭代器,适用于所有类型的标准容器。
    【解决方案3】:

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

    前两个是相同的类型,并且您正在传递 ( const_iterator, vec.end () ) - 并且 vec.end() 正在返回一个非常量迭代器(因为 vec 是一个非常量向量)。这会导致编译器拒绝 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多