vendredi 30 décembre 2016

Parameter pack expansion doesn't work

I tried to make multiplex of std::set, named NDos::set_multiplex, which can view the elements in perspective of various comparison objects. For example, a set of playing cards could be sorted with rank first and suit second, or suit first and rank second; NDos::set_multiplex enables to do this conveniently. NDos::set_multiplex does this by inheriting multiple std::sets, one storing the elements, and the others storing the iterator to the elements. NDos::IterComp is a Callable type that compares the elements refered by two iterators.

Here is the full code:

#ifndef SET_MULTIPLEX_H_INCLUDED
#define SET_MULTIPLEX_H_INCLUDED
#include <iterator>
#include <utility>
#include <memory>
#include <set>
#include "Iter.h"
namespace NDos {
    template <class T, class Comp0, class... Comps> class set_multiplex :
        private std::set<T, Comp0>,
        private std::set<
            typename std::set<T, Comp0>::iterator,
            IterComp<typename std::set<T, Comp0>::iterator, Comps>
        >... {
    private:
        typedef std::set<T, Comp0> Base0;
    public:
        using typename Base0::value_type;
        using typename Base0::allocator_type;
        using typename Base0::size_type;
        using typename Base0::difference_type;
        using typename Base0::reference;
        using typename Base0::const_reference;
        using typename Base0::pointer;
        using typename Base0::const_pointer;
        using typename Base0::iterator;
        using typename Base0::const_iterator;
        using typename Base0::reverse_iterator;
        using typename Base0::const_reverse_iterator;
#define Bases std::set<iterator, IterComp<iterator, Comps>>
        explicit set_multiplex(const Comp0 &comp0 = Comp0(), const Comps &...comps) : Base0(comp0),
            Bases(IterComp<iterator, Comps>{comps})... {}
        template <class InputIt> set_multiplex(InputIt first, InputIt last, const Comp0 &comp0 = Comp0(), const Comps &...comps)
        : set_multiplex(comp0, comps...) {
            insert(first, last);
        }
        set_multiplex(std::initializer_list<T> ilist, const Comp0 &comp0 = Comp0(), const Comps &...comps)
        : set_multiplex(std::make_move_iterator(ilist.begin()), std::make_move_iterator(ilist.end()), comp0, comps...) {}
        // copy constructor : default
        // move constructor : default
        // copy assignment operator : default
        // move assignment operator : default
        // destructor : default
        using Base0::get_allocator;
        using Base0::begin;
        template <class C> auto begin() noexcept {
            return std::set<iterator, IterComp<iterator, C>>::begin();
        }
        template <class C> auto begin() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::begin();
        }
        using Base0::cbegin;
        template <class C> auto cbegin() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::cbegin();
        }
        using Base0::end;
        template <class C> auto end() noexcept {
            return std::set<iterator, IterComp<iterator, C>>::end();
        }
        template <class C> auto end() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::end();
        }
        using Base0::cend;
        template <class C> auto cend() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::cend();
        }
        using Base0::rbegin;
        template <class C> auto rbegin() noexcept {
            return std::set<iterator, IterComp<iterator, C>>::rbegin();
        }
        template <class C> auto rbegin() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::rbegin();
        }
        using Base0::crbegin;
        template <class C> auto crbegin() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::crbegin();
        }
        using Base0::rend;
        template <class C> auto rend() noexcept {
            return std::set<iterator, IterComp<iterator, C>>::rend();
        }
        template <class C> auto rend() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::rend();
        }
        using Base0::crend;
        template <class C> auto crend() const noexcept {
            return std::set<iterator, IterComp<iterator, C>>::crend();
        }
        using Base0::empty;
        using Base0::size;
        using Base0::max_size;
        void clear() noexcept {
            Base0::clear();
            /*Bases::clear()...;*/
        }
        iterator insert(const T &value) {
            return emplace(value);
        }
        iterator insert(T &&value) {
            return emplace(std::move(value));
        }
        iterator insert(const_iterator pos, const T &value) {
            return emplace_hint(pos, value);
        }
        iterator insert(const_iterator pos, T &&value) {
            return emplace_hint(pos, std::move(value));
        }
        template <class InputIt> void insert(InputIt first, InputIt last) {
            while (first != last)
                insert(*first++);
        }
        void insert(std::initializer_list<T> ilist) {
            insert(std::make_move_iterator(ilist.begin()), std::make_move_iterator(ilist.end()));
        }
        template <class... Args> iterator emplace(Args &&...args) {
            iterator i0 = Base0::emplace(std::forward<Args>(args)...).first;
            /*Bases::insert(i0)...;*/
            return i0;
        }
        template <class... Args> iterator emplace_hint(const_iterator pos, Args &&...args) {
            iterator i0 = Base0::emplace_hint(pos, std::forward<Args>(args)...).first;
            /*Bases::insert(i0)...;*/
            return i0;
        }
        iterator erase(iterator pos) {
            /*Bases::erase(pos)...;*/
            return Base0::erase(pos);
        }
        iterator erase(const_iterator first, const_iterator last) {
            while (first != last)
                erase(first++);
        }
        size_type erase(const T &key) {
            iterator pos = find(key);
            if (pos == end())
                return 0;
            else {
                erase(pos);
                return 1;
            }
        }
        void swap(set_multiplex &other) noexcept {
            Base0::swap(other);
            /*Bases::swap(other)...;*/
        }
        using Base0::count;
        using Base0::find;
        using Base0::lower_bound;
        using Base0::upper_bound;
        using Base0::equal_range;
        using Base0::key_comp;
        template <class C> auto key_comp() const {
            return std::set<iterator, IterComp<iterator, C>>::key_comp().comp;
        }
        using Base0::value_comp;
        template <class C> auto value_comp() const {
            return std::set<iterator, IterComp<iterator, C>>::value_comp().comp;
        }
        friend void swap(set_multiplex &a, set_multiplex &b) noexcept {
            a.swap(b);
        }
#undef Bases
    };
}
#endif // SET_MULTIPLEX_H_INCLUDED

The commented expressions are the problem. The parameter packs aren't expanded properly. G++ 6.2 reports those errors each expansion:

error: expected ';' before '...' token
error: parameter packs not expanded with '...'

Why do these happen?

Aucun commentaire:

Enregistrer un commentaire