Reputation: 23551
I dont think my title is accurate so just go to the code.
namespace Fobaizer
{
template <typename T, typename C>
static T GetItemFromContainer(const C &container) {
T item = container[0]; // do something. 0 or iterator
return item;
}
}
Example:
MyClass myClass = Fobaizer::GetItemFromContainer<MyClass, vector<MyClass>(myVector);
or
MyClass myClass = Fobaizer::GetItemFromContainer<MyClass, deque<MyClass>(myDeque);
Here C is any container like std::deque
or std::vector
. I search for a C98 solution without any lib (boost, QT, etc.)
In fact, I am looking for something like the IEnumerable
of C#.
Any idea ?
Thank you.
Upvotes: 0
Views: 114
Reputation: 11
Why you want to do IEnumerable in C++, iterator is a good choice to iterate a collection.
Upvotes: 0
Reputation: 10780
What I would do is create a test that checks whether you can call std::begin
and std::end
on your container. And then use iterators to those containers and std::advance
to advance your iterators to where you need them.
The advantage of this method is then you can accept containers that don't overload operator[]
(like std::list
for example)
#include <utility>
#include <type_traits>
#include <vector>
#include <list>
namespace sfinae_true_details
{
template <class>
struct sfinae_true : std::true_type{};
}
template <class T>
auto test_has_begin_end(int) ->
sfinae_true_details::sfinae_true<decltype(std::begin(std::declval<T>()) ==
std::end(std::declval<T>())>;
template <class>
std::false_type test_has_begin_end(long);
template <class T>
struct has_begin_end : decltype(test_has_begin_end<T>(0)){};
int main()
{
static_assert(has_begin_end<std::vector<int> >::value, "");
static_assert(has_begin_end<std::list<float> >::value, "");
static_assert(has_begin_end<int>::value, "Expected to fail here");
return 0;
}
Then your usage would be:
template <typename T, typename C>
static T GetItemFromContainer(const C &container) {
static_assert(has_begin_end<C>::value, "Must pass a container for which "
"std::begin and std::end are callable");
T item = *std::begin(container); // do something. 0 or iterator
auto iter = std::begin(container);
std::advance(iter, 5);
item = *iter; // equivalent to container[5] for RandomAccessContainers
return item;
}
Upvotes: 1
Reputation: 11211
template <typename C>
static typename C::value_type GetItemFromContainer(const C & container) {
typename C::value_type item = container[0]; // do something. 0 or iterator
return item;
}
Basically every container defines the member typedefs:
value_type
reference
const_reference
iterator
const_iterator
So you can just use C::value_type
if you want to return by value, C::reference
if you want to return by reference, etc.
Upvotes: 5