admin管理员组文章数量:1399823
So I have a class called Layout
with the following code:
class Layout(){
protected:
std::vector<Frame*> frames;
public:
Layout(std::vector<Frame*> frames = {}) : frames(frames) {}
};
I am trying to achieve a high-level behavior where I can create layouts that inherit from the base layout
class:
class CustomLayout : public Layout{
//I am missing the correct constructor template here
};
So when I call the constructor, it populates the frames vector with the constructor arguments
CustomLayout* layout = new CustomLayout(
new Frame1(),
new Frame2(),
...
);
I wish to achieve this with template code:
template<typename... T>
CustomLayout::CustomLayout(T... frames)
: Layout(frames...) {
}
Any help is appreciated.
So I have a class called Layout
with the following code:
class Layout(){
protected:
std::vector<Frame*> frames;
public:
Layout(std::vector<Frame*> frames = {}) : frames(frames) {}
};
I am trying to achieve a high-level behavior where I can create layouts that inherit from the base layout
class:
class CustomLayout : public Layout{
//I am missing the correct constructor template here
};
So when I call the constructor, it populates the frames vector with the constructor arguments
CustomLayout* layout = new CustomLayout(
new Frame1(),
new Frame2(),
...
);
I wish to achieve this with template code:
template<typename... T>
CustomLayout::CustomLayout(T... frames)
: Layout(frames...) {
}
Any help is appreciated.
Share Improve this question asked Mar 24 at 23:26 Peter FerenczPeter Ferencz 763 silver badges8 bronze badges 3 |1 Answer
Reset to default 1There are several solutions that can solve your problem.
The solution 1 and solution 2 below are alternative solutions without parameter packs. And the solution 3 is the solution based on your idea to define a constructor with a parameter pack.
Why do I present the first two solutions? Because I don't think define a constructor with a parameter-pack to do this job is a good idea. Since a "layout" is a container of multiple frames logically, as STL containers and the C-style array do, this is the responsiblility of braced-init-lists. The parameter-pack should be used as something like
emplace
. Furthermore, the parameter-pack has no constrains on the types, although we know they should all be convertible toFrame*
.
Since the parameter of the constructor of Layout
is an std::vector<Frame>
, and the arguments you pass are elements of the std::vector<Frame>
, our goal is to call the constructor of std::vector<Frame>
the parameters of std::initializer_list<Frame>
.
Solution 1: Inherite the constructor of the base class explicitly
The first solution is to give CustomLayout
a constructor with a parameter of std::vector<Frame>
, so we can call the constructor of std::vector<Frame>
directly when passing arguments. The simplest way is to inherit the constructor of Layout
:
class CustomLayout : public Layout {
public:
using Layout::Layout;
};
or you can define it manually:
class CustomLayout : public Layout{
public:
CustomLayout(const std::vector<Frame*>& frames) : Layout(frames) {}
CustomLayout(std::vector<Frame*>&& frames) : Layout(std::move(frames)) {}
};
then when constructing an object of type CustomLayout
, we can use List-initialization to construct a temporary object of type std::vector<Frame*>
when passing arguments:
CustomLayout* layout = new CustomLayout({
new Frame1(),
new Frame2(),
});
Note that in ({...})
, the outer parentheses (...)
is to call the constructor with parameter std::vector<Frame*>
. And the inner braces {...}
is a braced-init-list, which will match the initializer-list constructor of std::vector<Frame*>
.
By the way, ({...})
and {{...}}
are both correct. Because in the latter manner, the outer braces {...}
can also match ordinary constructors since CustomLayout
has no initializer-list constructors.
Solution 2: Define an initializer-list constructor for CustomLayout
You can also define an initializer-list constructor for CustomLayout
, so that you can use List-initialization to initialize the CustomLayout
object directly.
class CustomLayout : public Layout{
public:
CustomLayout(std::initializer_list<Frame*> frames) : Layout(frames) {}
};
And then you can construct an object of type CustomLayout
directly with {...}
:
CustomLayout* layout = new CustomLayout{
new Frame1(),
new Frame2(),
};
And the braces {...}
as a braced-init-list will match the initializer-list constructor of CustomLayout
.
Solution 3: Define an constructor with a parameter-pack
Based on the idea of the questioner, if we define a constructor with a parameter-pack, we should use the parameters (whose types are template parameters) as arguments of the std::vector<Frame*>
, which is the parameter of the constructor of the base class object Layout
. This is the same as solution 1. So we should use ({...})
or {{...}}
to do that (the reason is presented in solution 1):
class CustomLayout : public Layout {
public:
template <typename... T>
CustomLayout(T... frames) : Layout({frames...}) {}
};
Then you can call it as:
CustomLayout* layout = new CustomLayout(
new Frame1(),
new Frame2() // No trailing commma ^_^! Too bad I think :(
);
By the way, in this senario, the parameters are all pointers, which are all scalar types, so there's no extra overhead when passing them by value. Generally, we should use std::forward
to avoid extra copies, if some of them are not trivially copiable, or even not copiable (if you wanna use std::unique_ptr<Frame>
) ^_^
:
class CustomLayout : public Layout {
public:
template <typename... T>
CustomLayout(T&&... frames) : Layout({std::forward<T>(frames)...}) {}
};
本文标签: cCpp parameter pack in constructorStack Overflow
版权声明:本文标题:c++ - Cpp parameter pack in constructor - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744224180a2596008.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Layout
? – JaMiT Commented Mar 25 at 1:09Layout(frames...)
should beLayout{frames...}
, otherwise the code looks correct. – NathanOliver Commented Mar 25 at 1:14Layout
constructor need one parameter of vector type, it must be calledLayout({frames...})
orLayout{{frames...}}
. – dalfaB Commented Mar 25 at 7:05