2

I would like to maintain a range-based and type-dependent method for insertion in my class.

The question is how you can implement this type-dependency by using iterators.

The following pseudo code should explain my problem:

class Test {

public:
    template<typename Iterator>
    void insert(const uint8 position, const Iterator begin, const Iterator end) {
        std::copy(begin, end, std::inserter(m_deque, m_deque.begin());
    }


private:
    std::deque<uint8> m_deque;

};


int main() {

    Test t;

    uint8 dataone[] = {0x00, 0xff};
    uint16 datatwo[] = {0xff, 0x00};
    std::vector<uint8> vecdataone = {0x00, 0xff};
    std::vector<uint16> vecdatatwo = {0xff, 0x00};

    t.insert(0, dataone, dataone + 2); // OKAY
    t.insert(0, datatwo, datatwo + 2); // SHOULD CAUSE AN ERROR
    t.insert(0, vecdataone.cbegin(), vecdataone.cend()); // OKAY
    t.insert(0, vecdatatwo.cbegin(), vecdatatwo.cend()); // SHOULD CAUSE AN ERROR

}

Greets.

Steve Murdock
  • 709
  • 1
  • 10
  • 20

2 Answers2

3

A static assertion will do the job:

void insert(const uint8 position, const Iterator begin, const Iterator end)
{
    static_assert(
        std::is_same<
            typename std::iterator_traits<Iterator>::value_type,
            uint8_t
        >::value,
        "Need iterators to uint8_t!"
    );
    // ....
}

I'd also suggest to use deque's own insert function instead of std::copy:

 m_deque.insert(s.deque.begin() + position, begin, end);

Being a member function and thus aware of internals, it can do a better job at optimizing the insertion.

jrok
  • 54,456
  • 9
  • 109
  • 141
  • Great thanks. I will try this. But is there also another way maybe like this: `template> insert(...)`? – Steve Murdock Mar 05 '14 at 18:19
  • @SteveMurdock There are other ways, like for example the technique used [here](http://stackoverflow.com/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function), but nothing as straightforward as that (it would at least require a fair amount of boilerplate code to get close to the syntax you want). Not worth it, IMO. – jrok Mar 05 '14 at 18:28
  • 1
    +1 for the mentioning of the member insert (as also mentioned in Effective STL). Since you use `static_assert`, you might as well use the other C++11 feature of `decltype(*begin)` instead of the longer traits extraction. – TemplateRex Mar 05 '14 at 19:58
  • @TemplateRex `decltype(*begin)` could be a const or non-const ref, so that doesn't buy us much. – jrok Mar 06 '14 at 12:32
1

I like (and upvoted) jrok's answer, but here's another approach using SFINAE, which means you can potentially allow matching to some other insert overrides if that makes sense. Error messages may be more cryptic than for jrok's answer though.

template<typename Iterator>
typename std::enable_if<
             std::is_same<typename std::iterator_traits<Iterator>::value_type,
                          uint8>::value,
             void>::type 
insert(const uint8 position, const Iterator begin, const Iterator end)
    ...

demo at http://ideone.com/c1d9jT

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252