gpt4 book ai didi

c++ - 如何区分 C++11 中的填充构造函数和范围构造函数?

转载 作者:太空宇宙 更新时间:2023-11-03 10:24:11 26 4
gpt4 key购买 nike

我怀疑 std::vector 的填充构造函数和范围构造函数的原型(prototype)(以及许多其他 STL 类型)在此 webpage 中给出不对,所以我实现了一个 NaiveVector模仿这两个原型(prototype)。

我的代码是:

#include <iostream>
#include <vector>
using namespace std;

template <typename T>
struct NaiveVector {
vector<T> v;
NaiveVector(size_t num, const T &val) : v(num, val) { // fill
cout << "(int num, const T &val)" << endl;
}

template <typename InputIterator>
NaiveVector(InputIterator first, InputIterator last) : v(first, last) { // range
cout << "(InputIterator first, InputIterator last)" << endl;
}

size_t size() const { return v.size(); }
};

int main() {
NaiveVector<int> myVec1(5,1); // A
cout << "size = " << myVec1.size() << endl;
for (auto n : myVec1.v) { cout << n << " "; }
cout << endl;

cout << "-----" << endl;

vector<int> vec({1,2,3,4,5});
NaiveVector<int> myVec2(vec.begin(), vec.end());// B
cout << "size = " << myVec2.size() << endl;
for (auto n : myVec2.v) { cout << n << " "; }
cout << endl;
}

输出是:

$ g++ overload.cc -o overload -std=c++11
$ ./overload
(InputIterator first, InputIterator last) // should be: (int num, const T &val)
size = 5
1 1 1 1 1
-----
(InputIterator first, InputIterator last)
size = 5
1 2 3 4 5

正如我从一开始就怀疑的那样,编译器无法正确地区分这两个构造函数。那么我的问题是:std::vector怎么办?的填充构造函数和范围构造函数有区别吗?

换句话说:如何实现这个NaiveVector的两个构造函数?

This question seems to be a duplicate of this question but the answer is not satisfying. Additionally, C++11 itself doesn't provide a is_iterator<>.. (MSVC has lots of hacks).

编辑:允许将右值绑定(bind)到常量左值引用,因此 NaiveVector 的第一个构造函数适用于 A .

最佳答案

C++03

[lib.sequence.reqmts]/9

For every sequence defined in this clause and in clause 21:

  • the constructor

    template <class InputIterator>
    X(InputIterator f, InputIterator l, const Allocator& a = Allocator())

    shall have the same effect as:

    X(static_cast<typename X::size_type>(f),
    static_cast<typename X::value_type>(l),
    a)

    if InputIterator is an integral type.

...

[lib.sequence.reqmts]/11

One way that sequence implementors can satisfy this requirement is to specialize the member template for every integral type. Less cumbersome implementation techniques also exist.

换句话说,标准说如果范围构造函数被重载决议选中,但“迭代器”类型实际上是一个整数类型,它必须通过转换其参数类型来委托(delegate)给填充构造函数以强制后者是完全匹配。

C++11/C++14

[序列.reqmts]/14

For every sequence container defined in this clause and in clause 21:

  • If the constructor

    template <class InputIterator>
    X(InputIterator first, InputIterator last,
    const allocator_type& alloc = allocator_type())

    is called with a type InputIterator that does not qualify as an input iterator, then the constructor shall not participate in overload resolution. ...

[序列.reqmts]/15

The extent to which an implementation determines that a type cannot be an input iterator is unspecified, except that as a minimum integral types shall not qualify as input iterators.

这或多或少是标准提示您使用 SFINAE 的方式(与 C++03 相比,它在 C++11 中可靠地工作)。

C++17

措辞类似,除了关于整数类型不是迭代器的段落已移至[container.requirements.general]/17。 .

结论

你可以写你的范围构造函数看起来像这样:

template <typename InputIterator,
typename = std::enable_if<is_likely_iterator<InputIterator>>::type>
NaiveVector(InputIterator first, InputIterator last)

is_iterator 辅助模板可能简单地取消整数类型的资格并接受所有其他类型,或者它可能做一些更复杂的事情,例如检查是否有 std::iterator_traits指示类型是输入迭代器(或更严格)的特化。参见 libstdc++ source , libc++ source

这两种方法都符合 C++11 及更高版本中 std::vector 标准的强制行为。建议使用后一种方法(并且将与真正的 std::vector 在典型实现中可能执行的操作一致),因为如果您传递可隐式转换为填充期望的类型的参数构造函数,您会希望该类“做正确的事”,而不是选择范围构造函数只是为了让它无法编译。 (虽然我怀疑这相当不常见。)相对于 C++03 std::vector,它是一个“一致的扩展”,因为在那种情况下构造函数调用将无法编译。

关于c++ - 如何区分 C++11 中的填充构造函数和范围构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45847787/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com