Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I use enable_if to enable a template function based on what type an iterator iterates over?

I currently have a function that looks like this:

    template<typename input_iterator>
    std::string doit(input_iterator beg, input_iterator end)
    {
        static_assert(sizeof(*beg) == 1, "Size one only, please");
        return do_something(beg, end);
    }

This works fine in that

std::vector<uint8_t> v1 {1, 2, 3};
doit(v1.begin(), v1.end());

succeeds while

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

std::vector<int> v2 {1, 2, 3};
doit(v2.begin(), v2.end());

fails at the static_assert.

What I would prefer is to have the code fail at the call site rather than within the called function, and get rid of the static_assert.

I have tried a number of things including variations on enable_if but I haven’t hit on the right combination. My latest attempt was

    template<typename input_iterator, 
       std::enable_if<sizeof(std::iterator_traits<input_iterator>::value_type) == 1>>
    std::string doit(input_iterator beg, input_iterator end)
    {
        return do_something(beg, end);
    }

but this resulted in no-matching-function failures no matter what type my iterators are.

Can someone please point me in the right direction? I’m not looking for concepts, I need code that will compile using C++17.

Thanks.

>Solution :

This seems to do the trick:

https://godbolt.org/z/6GjcoYrzG

#include <string>
#include <vector>
#include <stdexcept>
#include <type_traits>

template<typename input_iterator>
auto doit(input_iterator beg, input_iterator end)
 -> std::enable_if_t<sizeof(*beg) == 1, std::string>
{
    throw std::runtime_error("");
    // return do_something(beg, end);
}

int main() {
    std::vector<uint8_t> v1 {1, 2, 3};
    doit(v1.begin(), v1.end());

    std::vector<int> v2 {1, 2, 3};
    doit(v2.begin(), v2.end());  // error: no matching function for call to 'doit'

    return 0;
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading