【问题标题】:Mixin constructors nested pack expansionMixin 构造函数嵌套包扩展
【发布时间】:2021-07-17 19:16:53
【问题描述】:

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

这是我目前拥有的:

#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 构造函数中指定的参数调用所有类。 Der1Der2 实际上继承自同一个基类。

我现在使用 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

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

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

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

但是我仍然想知道为什么没有调用正确的构造函数

【问题讨论】:

  • 似乎 gcc 错误..
  • @Jarod42 看起来像,最重要的是,即使使用 clang,它也没有像我期望的那样做,基类是默认构造的
  • @rustyx 我刚刚尝试过,但我仍然看到调用了默认 ctor。
  • stackoverflow.com/a/26099873/9072753MixinVisitor(Args&amp;&amp;... args) : Mixin{std::forward&lt;Args&gt;(args)...}..., Base{args...} {} 似乎工作 vv
  • 您可以通过使用大括号而不是 Mixin{std::forward&lt;Args&gt;(args)...}... 来解决(大概)gcc 错误。这样,两个编译器至少会给出一致的结果。

标签: c++ inheritance variadic-templates virtual mixins


【解决方案1】:

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

如 cmets 中所述,将 :Mixin(std::forward&lt;Args&gt;(args)...)... 更改为 :Mixin{std::forward&lt;Args&gt;(args)...}... 即可解决问题。

关于为什么调用默认的Base构造函数:虚基类的构造函数直接被最派生类的构造函数调用。在这种情况下,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)...}...
  {
  }

  . . .

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

【讨论】:

    猜你喜欢
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 2013-11-15
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多