Reputation: 535
Why doesn't C++ provide us with a constructor which takes an array as an argument? Alternatively, is there anything wrong with defining the following function?
template <class T>
std::set<T> ArrayToSet(T array[]) {
return std::set<T>(array, array + sizeof(array) / sizeof(array[0]));
}
I think the answer might come down to ideas of dynamic memory allocation, but I'd like to hear some feedback on this.
Edit: I am not using C++11.
Upvotes: 3
Views: 4647
Reputation: 15872
Why doesn't C++ provide us with a constructor which takes an array as an argument?
Why would it? A std::set
is not an array, and it already has a constructor that takes iterators to initialize it, so adding another constructor for an array is unnecessary. std::vector
IS an array and even it does not have a constructor that takes an array.
Alternatively, is there anything wrong with defining the following function?
Yes and no. It is unnecessary as you can just write
MyType myArray[mySize];
std::set<MyType> mySet(myArray, myArray + sizeof(myArray) / sizeof(array[0]);
// or std::set<MyType> mySet(myArray, myArray + mySize);
// or std::set<MyType> mySet(std::begin(myArray), std::end(myArray)); c++11
It isn't really worthy of its own function.
If you really want to write a function to help you out, I'd approach it by porting std::begin
and std::end
to C++03. Those would at least be more usable than a function specifically to create a std::set
.
It would look exactly like what Konrad posted in his answer.
Upvotes: 5
Reputation: 545528
Alternatively, is there anything wrong with defining the following function?
There is: it doesn’t work.
You cannot pass variable-length C-style arrays to functions. The T array[]
syntax in an argument list is a synonym for T* array
: a raw pointer is passed, not an argument.
You can, however, pass fixed-sized arrays by reference (i.e. T (&array)[5]
works). To make this work for different array lengths you need to use a non-type template argument:
template <class T, std::size_t N>
std::set<T> ArrayToSet(T (&array)[N]) {
return std::set<T>(array, array + N);
}
– But I agree in this with Zac: the function is over-specific (or, the other way round: not generic enough). There is already a universal collection-construction method, via iterators. So the correct way is to use C++11’s std::begin
and std::end
facility, and if you cannot use C++11, then the correct way is to write them yourself:
template <typename T, std::size_t N>
T* begin(T (&array)[N]) {
return array;
}
template <typename T, std::size_t N>
T* end(T (&array)[N]) {
return array + N;
}
Upvotes: 6
Reputation: 8975
std::set
does not need to provide a constructor for C style arrays, because it is possible to construct from them already using iterators - furthermore it is not easy to construct from an array, because you could try to construct from T *
, which does not convey the array length, or whether it's an array at all.
To do this, we use a template trick to determine the array size and use the iterator constructor:
template <typename T, size_t N>
std::set<T> ArrayToSet(T (& array)[N]) {
return std::set<T>(&array[0], &array[0]+N);
}
Note that, as stated in the comments, this will not work for T *
types. You could overload for that giving an additional parameter arr_length
or something. In this case sizeof
doesn't work either, it would just give you the size of the pointer, not the array.
Upvotes: 3