问题
Sequence containers need to have fill constructors and range constructors, i.e. these must both work, assuming MyContainer
models a sequence container whose value_type
is int
and size_type
is std::size_t
:
// (1) Constructs a MyContainer containing the number '42' 4 times.
MyContainer<int> c = MyContainer<int>(4, 42);
// (2) Constructs a MyContainer containing the elements in the range (array.begin(), array.end())
std::array<int, 4> array = {1, 2, 3, 4};
MyContainer<int> c2 = MyContainer<int>(array.begin(), array.end());
Trouble is, I'm not sure how to implement these two constructors. These signatures don't work:
template<typename T>
MyContainer<T>::MyContainer(const MyContainer::size_type n, const MyContainer::value_type& val);
template<typename T>
template<typename OtherIterator>
MyContainer<T>::MyContainer(OtherIterator i, OtherIterator j);
In this case, an instantiation like in example 1 above selects the range constructor instead of fill constructor, since 4
is an int, not a size_type
. It works if I pass in 4u
, but if I understand the requirements correctly, any positive integer should work.
If I template the fill constructor on the size type to allow other integers, the call is ambiguous when value_type
is the same as the integer type used.
I had a look at the Visual C++ implementation for std::vector
and they use some special magic to only enable the range constructor when the template argument is an iterator (_Is_iterator<_Iter>
). I can't find any way of implementing this with standard C++.
So my question is... how do I make it work?
Note: I am not using a C++11 compiler, and boost is not an option.
回答1:
I think you've got the solution space right: Either disambiguate the call by passing in only explicitly size_t
-typed n
s, or use SFINAE to only apply the range constructor to actual iterators. I'll note, however, that there's nothing "magic" (that is, nothing based on implementation-specific extensions) about MSVC's _Is_iterator
. The source is available, and it's basically just a static test that the type isn't an integral type. There's a whole lot of boilerplate code backing it up, but it's all standard C++.
A third option, of course, would be to add another fill constructor overload which takes a signed size.
来源:https://stackoverflow.com/questions/21042872/how-to-implement-fill-constructor-and-range-constructor-for-sequence-containers