Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template for "AnySTLContainer<int>" c++

I am looking for a way to provide a function that takes a templated (STL) container, but requires its elements to be of a certain type (e.g. int).

These function calls should be VALID:

std::vector<int> Argument;
void foo( Argument );

std::list<int> Argument
void foo( Argument );

std::deque<int> Argument
void foo( Argument );

...etc

These function calls should be INVALID:

std::vector<float> Argument;
void foo( Argument );

std::list<double> Argument
void foo( Argument );

std::deque<char> Argument
void foo( Argument );

...etc

Is there a way to template "foo" such that containers of int are accepted, but containers with different element types are not accepted ?

Best, Ben

like image 947
S.H Avatar asked Aug 20 '14 20:08

S.H


2 Answers

Use the Standard Library semantics :

  • Pass a pair of iterators to foo, not a container : it makes your function much more generic
  • Use std::iterator_traits<Iterator>::value_type to get to the value type
  • static_assert the value type of the Iterator to be an int (or whatever type you want)

Example :

#include <list>
#include <vector>

template<typename Iterator>
void foo(Iterator begin, Iterator end)
{
    static_assert(std::is_same<int, typename std::iterator_traits<Iterator>::value_type>::value, 
                                "Invalid value type : must be int");
}

int main() {
    std::list<int> l1;
    std::vector<int> v1;

    foo(std::begin(l1), std::end(l1)); // OK
    foo(std::begin(v1), std::end(v1)); // OK

    std::vector<float> v2;
    foo(std::begin(v2), std::end(v2)); // Doesn't compile
}

Live demo

Note:

  • If foo needs to access specific member functions of the container (as noted by Deduplicator, this might happen for performance reasons), then you might need to stick with the Container argument :

Example : (Note the difference for getting at the value_type, as pointed by MooingDuck, this is required to make it work with arrays):

template <typename Container>
void foo(const Container& c)
{

    static_assert(std::is_same<int, std::iterator_type<decltype(std::begin(c))>::value_type>::value, "Invalid value type : must be int");

   // Use c member function(s)
}
like image 156
quantdev Avatar answered Oct 04 '22 21:10

quantdev


STL containers have the typedef value_type, so you may use it.

Then you may forbid with static_assert:

template <typename Container>
void foo(const Container& )
{
    static_assert(std::is_same<int, typename Container::value_type>::value, "expect int type");
}

or via SFINAE

template <typename Container>
typename std::enable_if<std::is_same<int, typename Container::value_type>::value>::type
foo(const Container& )
{
}
like image 21
Jarod42 Avatar answered Oct 04 '22 20:10

Jarod42