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。
Der1
和 Der2
实际上继承自同一个 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。
我正在尝试实现一个 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。
Der1
和 Der2
实际上继承自同一个 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。