【问题标题】:Parameter pack expansion doesn't work参数包扩展不起作用
【发布时间】:2016-12-30 08:02:00
【问题描述】:

我尝试制作std::set的复用,命名为NDos::set_multiplex,它可以从各种比较对象的角度查看元素。例如,可以将一组扑克牌排序为第一花色第二,或花色第一和第二。 NDos::set_multiplex 可以方便地做到这一点。 NDos::set_multiplex 通过继承多个 std::sets 来做到这一点,一个存储元素,另一个存储元素的迭代器。 NDos::IterComp 是一个 Callable 类型,用于比较两个迭代器引用的元素。

代码如下:

/*...*/
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::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>>
        /*constructors*/
        // copy constructor : default
        // move constructor : default
        // copy assignment operator : default
        // move assignment operator : default
        // destructor : default
        /*...*/
        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)...;
        }
        /*...*/
#undef Bases
    };
}

参数包未正确展开。 G++ 6.2 每次扩展都会报告这些错误:(在函数 clearemplaceemplace_hinteraseswap

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

为什么会这样?

【问题讨论】:

  • 请发布更完整的编译器输出。某处会有一个行号(并告诉我们那是哪一行)。还要尝试将您的代码减少到关键部分。
  • @Christoph 好的,我做到了。

标签: c++ c++11 parameters


【解决方案1】:

在 C++11 中你不能简单地这样做:

Bases::clear()...;

您以这种方式使用过... 的所有其他地方也会发生同样的情况:

Bases::insert(i0)...;
Bases::erase(pos)...;
Bases::swap(other)...;

尝试使用这样的东西:

void clear() noexcept {
    Base0::clear();
    int _[] = { 0, (Bases::clear(), 0)... };
    (void)_; // silent warnings, nothing more
}

这是等待 C++17 及其折叠表达式时常用的技巧。


特别提到swap 函数:如果将otherBase0 交换,则other 理论上将在交换后包含Base0 中的数据。再次将其用于另一个交换似乎不是一个好主意。
也许您应该查看 swap 函数的实现。

【讨论】:

  • Base0::swap(other) 期间,不会复制或移动任何元素,并且所有迭代器都保持有效。所以这没有问题。
猜你喜欢
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 2014-02-20
  • 2019-03-21
  • 2011-08-18
  • 2012-03-02
  • 1970-01-01
相关资源
最近更新 更多