Home > OS >  Function template accepting only non integral types (specifially bidirectional iterators)
Function template accepting only non integral types (specifially bidirectional iterators)

Time:11-15

I need a function template that only accepts non-integral types, if the arguments are iterators i made (i made my own class and using enable_if and a tag i manage to deduce whether or not the params are the iterators I created or not)

template <typename InputIterator>
        foo (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type(),
        typename ft::enable_if<InputIterator::InputIter, InputIterator>::type = NULL)
        {
            insert(begin(), first, last);
        }

I want to make sure the parameters passed to the function are either my own iterator or a bidirectional iterator, however i thought this would be much easier if i could just check if the "InputIterator" is simply non integral but i dont know what is needed precisely to implement it, and am not sure if its a good idea since at the end of the day what i really need is to make sure its an iterator that fits my criterias.

How should i proceed ? what functions are worth looking into ?

am using -std=c 98, so am sticking to the c 98 libraries, so no c 11 or after functionality that came out after 98.

CodePudding user response:

You can create some type traits yourself to get SFINAE.

Since it's C 98, you can start by creating some traits that are included in the newer standards:

template<class T, class U>
struct is_same { static const bool value; };
template<class T, class U> const bool is_same<T,U>::value = false;
 
template<class T>
struct is_same<T, T> { static const bool value; };
template<class T> const bool is_same<T,T>::value = true;

template<bool B, class T = void> struct enable_if {};
 
template<class T> struct enable_if<true, T> { typedef T type; };

You can then build your own trait:

template<class It>
struct accepted_iterator {
    static const bool value;
};

#include <iterator>
template<class It>
const bool accepted_iterator<It>::value = // add the accepted iterator categories here:
    is_same<typename std::iterator_traits<It>::iterator_category,
                   std::bidirectional_iterator_tag>::value ||
    is_same<typename std::iterator_traits<It>::iterator_category,
                   std::random_access_iterator_tag>::value;

And checking the iterator type, SFINAE style:

template <typename InputIterator>
typename enable_if<accepted_iterator<InputIterator>::value>::type
foo (InputIterator first, InputIterator last) {

}

CodePudding user response:

Since you are limited to C 98 it is best to try animate SFINAE tools available in later versions c 03. This way code will be more familiar for future maintainer.

For example C 98 do not have following tools: std::enable_if, std::iterator_traits std::is_integral.

Your case is quite simple, so it is not hard, but lots of boiler plate is needed:

#include <numeric>

template <typename T>
struct is_integer {
    static const bool value = false;
};

template <>
struct is_integer<int> {
    static const bool value = true;
};

template <>
struct is_integer<char> {
    static const bool value = true;
};

template <>
struct is_integer<long int> {
    static const bool value = true;
};

template <>
struct is_integer<unsigned int> {
    static const bool value = true;
};

template <>
struct is_integer<unsigned char> {
    static const bool value = true;
};

template <>
struct is_integer<unsigned long int> {
    static const bool value = true;
};

template <bool codition, typename T = void>
struct enable_if {};

template <typename T>
struct enable_if<true, T> {
    typedef T type;
};

template <typename T>
struct iterator_traits {
    typedef typename T::value_type value_type;
};

template <typename T>
struct iterator_traits<T*> {
    typedef T value_type;
};

template <typename InputIterator>
typename enable_if<
        is_integer<
                typename iterator_traits<InputIterator>::value_type
            >::value,
        typename iterator_traits<InputIterator>::value_type
    >::type
foo(InputIterator first, InputIterator last) {
    typedef typename iterator_traits<InputIterator>::value_type type;
    return std::accumulate(first, last, type(0));
}

void test() {
    int arr[3] = {1, 3, 4};
    foo(arr, arr   3);
}

#ifdef TEST_FAILURE
void test_faiure() {
    double arr[3] = {1, 3, 4};
    foo(arr, arr   3);
}
#endif

https://godbolt.org/z/f4jvoKb5E

I didn't check what was the status of boost for C 98 (especially that you didn't specified compiler), but you should check if this is already done there

  • Related