问题描述
我正在尝试实现一个 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
构造函数中指定的参数调用所有类。
Der1
和 Der2
实际上继承自同一个 Base 类。
我现在的代码可以用 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
此外,输出不是我所期望的,这可能是由于虚拟继承。
default ctor
4204112
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
构造函数:虚基类的构造函数被最派生类的构造函数直接调用。在这种情况下,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)...}...
{
}
. . .
我不知道您的具体用例,但虚拟基类通常是带有默认构造函数的非常基本的样板类,以免不必要地限制使用。这样,mixin 就可以拥有不依赖于 base 的 ctors。