简体   繁体   中英

How do I static_assert the type that an iterator dereferences to?

template <typename InputIterator>
MyFun(const InputIterator begin, const InputIterator end)
{
    // I want to static_assert that decltype(*begin) == SomeType
}

How can I do this? I'm thinking static_assert(std::is_same<*InputIterator,SomeType>) but that of course does not work...

std::iterator_traits :

static_assert(is_same<typename std::iterator_traits<InputIterator>::value_type, 
               SomeType>::value, "");

An alternative using decltype , with a note in passing that it often produces a reference (but may not!).

// If you want to assert that the dereferenced item is indeed a reference
static_assert(std::is_same<decltype(*begin), SomeType&>::value, "");

// If you are only interested in the "bare" type
// (equivalent to Jesse's providing iterator_traits was properly specialized)
static_assert(std::is_same<
    typename std::remove_reference<decltype(*begin)>::type,
    SomeType
>::value, "");

I would rather use std::is_convertible instead of std::is_same and const SomeType& instead of SomeType because usually, the convertibility to const SomeType& is all we need from the iterator.

    static_assert(
        std::is_convertible<decltype(*begin), const SomeType&>::value,
        "Input parameters must be iterators over objects convertible to 'SomeType'."
    );

In addition, const SomeType& shall be changed to SomeType& if the data is going to be modified through the iterators. This is essentially useful in case of inheritance where iterators over child objects are passed to a function receiving iterators of parent class.

Here is a concrete example:

#include <type_traits>
#include <vector>
#include <iostream>


struct Animal {
    int x;

    inline void print() const {
        std::cout << "x = " << x << std::endl;
    }

    inline int modify() {
        return ++x;
    }

    virtual ~Animal() = default;
};

struct Cat: public Animal {
};

struct Dog: public Animal {
};


template<typename I>
inline void printAnimals(I begin, I end) {
    static_assert(
        std::is_convertible<decltype(*begin), const Animal&>::value,
        "Input parameters must be iterators over objects of type 'Animal'."
    );
    for (I it = begin; it != end; ++it) {
        const Animal& a = *it;
        a.print();
    }
    std::cout << "---------" << std::endl;
}


template<typename I>
inline void modifyAnimals(I begin, I end) {
    static_assert(
        std::is_convertible<decltype(*begin), Animal&>::value,
        "Input parameters must be iterators over objects of type 'Animal'."
    );
    for (I it = begin; it != end; ++it) {
        Animal& a = *it;
        a.modify();
    }
}

int main() {
    std::vector<Dog> dogs(2);
    dogs[0].x = 10;
    dogs[1].x = 20;
    printAnimals(dogs.begin(), dogs.end());
    modifyAnimals(dogs.begin(), dogs.end());
    printAnimals(dogs.begin(), dogs.end());

    std::vector<Cat> cats(3);
    cats[0].x = 100;
    cats[1].x = 110;
    cats[2].x = 120;
    printAnimals(cats.begin(), cats.end());
    modifyAnimals(cats.begin(), cats.end());
    printAnimals(cats.begin(), cats.end());
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM