c++ - 如何为 const 模板参数定义复制构造函数?

标签 c++ stl constants std copy-constructor

我正在创建自定义迭代器,但我无法满足创建 const 的场景。迭代器并用非 const 初始化它begin() .根据 STL,这是合法的,可以用 std::string:

来证明
#include <string>

using namespace std;

int main() {
    string::iterator a;
    string::const_iterator b = a;

    return 0;
}

我不知道如何让它工作:

template<typename T>
class some_class {
};

int main() {
    some_class<int> a;

    // Works OK!
    const some_class<int> const_b = a;

    // error: conversion from 'some_class<int>' to non-scalar type 'const some_class<const int>'
    const some_class<const int> const_c = a;

    return 0;
}

更新

@ALEXANDER KONSTANTINOV提供了一个解决方案,但它不满足所有可能的 STL 测试用例。我正在测试 @Bo Persson接下来的建议。将构造函数更改为 const some_class<U>& other将允许它编译,然后 iterator a = const_iterator b也会错误地为真。

#include <string>

using namespace std;

template<typename T>
class some_class {
public:
    some_class() {
    }

    template<typename U>
    some_class(some_class<U>& other) {
    }
};

namespace name {
    typedef some_class<int> iterator;
    typedef const some_class<const int> const_iterator;
}

int main() {
    string::iterator a;
    string::const_iterator b = a;
    const string::iterator c;
    string::iterator d = c;
    string::const_iterator e = c;

    name::iterator f;
    name::const_iterator g = f;
    const name::iterator h;
    name::iterator i = h;
    name::const_iterator j = h; // <- Error

    return 0;
}

更新

关于添加 const 似乎有些困惑给构造函数。这是一个测试用例:

// This is not allowed by the STL
//string::const_iterator _a;
//string::iterator _b = _a; // <- Error!

// This should NOT compile!
name::const_iterator _a;
name::iterator _b = _a;

最佳答案

首先 - 你不能假设 std::string::const_iterator 只是常规迭代器的“const 版本” - 就像这样 const std::string::iterator.

当您查看 STL 库实现时(这只是 gcc4.9.2 basic_string 的 STL header 中的示例):

  typedef __gnu_cxx::__normal_iterator<pointer, basic_string>  iterator;
  typedef __gnu_cxx::__normal_iterator<const_pointer, basic_string>
                                                        const_iterator;

如您所见 - 两个迭代器的不同之处在于返回指针值 - pointerconst_pointer - 就是这种情况 - “const 迭代器”不是无法更改 - 但会返回 const 指针/引用,因此您无法修改迭代器迭代的值。

因此 - 我们可以进一步调查并查看如何实现从非 const 版本到 const 版本的所需复制:

  // Allow iterator to const_iterator conversion
  template<typename _Iter>
    __normal_iterator(const __normal_iterator<_Iter,
          typename __enable_if<
           (std::__are_same<_Iter, typename _Container::pointer>::__value),
          _Container>::__type>& __i) _GLIBCXX_NOEXCEPT
    : _M_current(__i.base()) { }

所以,基本上 - 这个构造函数接受同一模板的任何实例 (__normal_iterator) - 但它有 enable_if 闭包只允许 const 指针的实例。

我相信你也会对你的情况做同样的事情

  1. 拥有真正的 const_iterator - 而不仅仅是常规迭代器的 const 版本
  2. 并且有来自 const_iterator 的模板构造函数,带有 enable_if 限制以禁止从任何东西构造(我的意思是迭代器超过 ints 来自迭代器超过 std::strings)

按照你的例子:

#include <type_traits>

template<typename T>
class some_class {
public:
    some_class() {
    }

    template <typename U>
    using allowed_conversion_from_non_const_version = std::enable_if_t<std::is_same<std::remove_cv_t<T>,U>::value>;

    template<typename U, typename EnableIf = allowed_conversion_from_non_const_version<U>>
    some_class(const some_class<U>&) {
    }

    template<typename U, typename EnableIf = allowed_conversion_from_non_const_version<U>>
    some_class& operator = (const some_class<U>&) {
    }
};

从这个例子中可以看出两点:

  1. 还需要赋值运算符
  2. 您应该只启用从非常量到常量的版本 - 这是通过 enable_if/remove_cv 的组合实现的(remove_const 也有效- 但为什么不也构建 volatile 版本 - 反正 cvconst)

关于c++ - 如何为 const 模板参数定义复制构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35309197/

相关文章:

C++ 列表排序函数

c++ - "universal-character-name encountered in source"警告的目的是什么?

c++ - 用STL做新软件好不好?

c++ - 使非成员函数常量

c++ - 为什么访问函数必须是 const?漏洞在哪里?

c++ - 了解移位运算符

C++ 如何将二进制文件的一部分复制到新文件?

c++ - back_inserter 是如何工作的?

c++ - 程序员应该使用 STL 还是编写自己的代码?

c++ - 从文件初始化静态常量成员