Mixin构造函数嵌套包扩展

Mixin constructors nested pack expansion

我正在尝试实现一个 Mixin class,但遇到了一些问题:

这是我目前拥有的:

#include <iostream>
#include <string>

using namespace std;

struct Base
{
    Base()
    {
        cout << "default ctor" << endl;
    }
    
    Base(int i, string s)
        :i_(i)
            ,s_(s)
    {
        cout << "i: " << i << " s:" << s << endl;
    }
    virtual ~Base() = default;
    virtual void handle() {};
    
    int i_;
    string s_;
};

struct Der1 : virtual public Base
{
    using Base::Base;
};

struct Der2 : virtual public Base
{
    using Base::Base;
};

template<class... Mixin>
class MixinVisitor : public Mixin... {
public:
  template <typename... Args>
  MixinVisitor(Args&&... args) : Mixin(std::forward<Args>(args)...)...
  {
  }

};



int main()
{
    MixinVisitor<Der1, Der2> m(10, "var");
    cout << m.i_ << endl;
}

我希望使用 MixinVisitor 构造函数中指定的参数调用所有 classes。 Der1Der2 实际上继承自同一个 Base class。

我现在用 Clang 编译的代码,但用 GCC 编译失败。 虽然 Clang 的行为不是我所期望的,因为我看到输出只是调用了默认构造函数。

gcc错误如下:

prog.cc:44:68: error: invalid use of pack expansion expression
   44 |   MixinVisitor(Args&&... args) : Mixin(std::forward<Args>(args)...)...
      |                                                                    ^~~
1

而且输出不是我所期望的,这可能是由于虚拟继承。

我只看到默认的 ctor 被调用:

default ctor
4204112

如何强制调用正确的构造函数?

编辑: 感谢评论,gcc 问题有一个解决方法:

  MixinVisitor(Args&&... args) : Mixin{std::forward<Args>(args)...}...

不过我还是想知道为什么没有调用正确的构造函数

GCC 错误 invalid use of pack expansion expression 是一个错误 #88580。似乎是 GCC 10 中的回归。

如评论中所述,将 :Mixin(std::forward<Args>(args)...)... 更改为 :Mixin{std::forward<Args>(args)...}... 即可解决问题。

关于调用默认Base构造函数的原因:虚拟基础class的构造函数被最派生的class的构造函数直接调用。在本例中,MixinVisitor直接调用了Base的构造函数,由于你没有提到调用哪一个,所以调用默认的。这就是虚拟继承的工作原理(另请参阅 FAQ)。

如果您想调用 Base(int i, string s),请明确指定,例如像这样:

template<class... Mixin>
class MixinVisitor : public Mixin... {
public:
  template <typename... Args>
  MixinVisitor(Args&&... args)
      : Base(std::forward<Args>(args)...), Mixin{std::forward<Args>(args)...}...
  {
  }

  . . .

我不知道你的具体用例,但虚拟基础通常是一个非常基本的样板 class,带有默认的 ctor,以免不必要地限制使用。这样 mixin 就可以拥有不依赖于基础的 ctors。