模板 Class 以不同方式实现 Variadic Constructor:每个版本的优缺点是什么?
Template Class With Variadic Constructor implemented in different ways: What are the benefits and downfalls of each version?
我用两种不同的方式编写了这个模板 class:一种使用可变参数构造函数,另一种使用 std::initializer_list<T>
。出于这个问题的目的,我将以不同的方式命名 classe,但请注意,在我的项目中它是相同的 class,因为两个版本都做同样的事情。我想知道这两个版本的优点和缺点是什么。哪个更有效,为什么?
可变版本:
#include <vector>
#include <memory>
template<typename T>
class Nodes {
private:
unsigned m_numParams;
std::vector<std::shared_ptr<T>> m_vNodes;
public:
Nodes() : m_numParams(0), m_vNodes { nullptr } {}
template <typename ... Ts >
explicit Nodes( Ts&&...ts ) :
m_numParams( sizeof...(Ts) ),
m_vNodes{ std::make_shared<T>( std::forward<Ts>( ts ) )... }
{}
}; // Nodes
int main() {
int x = 3;
int y = 5;
int z = 7;
Nodes<int> nodes( x, y, z );
return 0;
}
std::initializer_list<T>
版本
#include <vector>
#include <memory>
template<typename T>
class Nodes2 {
private:
unsigned m_numParams;
std::vector<std::shared_ptr<T>> m_vNodes;
public:
Nodes2() : m_numParams(0), m_vNodes{ nullptr } {}
explicit Nodes2( std::initializer_list<T> ini ) :
m_numParams( ini.size() ) {
for ( auto&& e : ini ) {
m_vNodes.push_back( std::make_shared<T>( e ) );
}
}
}; // Nodes2
int main() {
int x = 3;
int y = 3;
int z = 3;
std::initialize_list<int> ini{ x, y, z };
Nodes2<int> nodes2( ini );
return 0;
}
如果您正在创建一个通用容器,并且不知道将要存储的对象类型 (T
),并且您希望允许移动构造,那么可变参数版本更好.
这是因为您无法从 std::initializer_list
移动,所以您的第二个版本将不得不复制构建 T
对象。
来自cppreference
:
An object of type std::initializer_list<T>
is a lightweight proxy object that provides access to an array of objects of type const T
无法对存储的对象数组进行可变访问。
我用两种不同的方式编写了这个模板 class:一种使用可变参数构造函数,另一种使用 std::initializer_list<T>
。出于这个问题的目的,我将以不同的方式命名 classe,但请注意,在我的项目中它是相同的 class,因为两个版本都做同样的事情。我想知道这两个版本的优点和缺点是什么。哪个更有效,为什么?
可变版本:
#include <vector>
#include <memory>
template<typename T>
class Nodes {
private:
unsigned m_numParams;
std::vector<std::shared_ptr<T>> m_vNodes;
public:
Nodes() : m_numParams(0), m_vNodes { nullptr } {}
template <typename ... Ts >
explicit Nodes( Ts&&...ts ) :
m_numParams( sizeof...(Ts) ),
m_vNodes{ std::make_shared<T>( std::forward<Ts>( ts ) )... }
{}
}; // Nodes
int main() {
int x = 3;
int y = 5;
int z = 7;
Nodes<int> nodes( x, y, z );
return 0;
}
std::initializer_list<T>
版本
#include <vector>
#include <memory>
template<typename T>
class Nodes2 {
private:
unsigned m_numParams;
std::vector<std::shared_ptr<T>> m_vNodes;
public:
Nodes2() : m_numParams(0), m_vNodes{ nullptr } {}
explicit Nodes2( std::initializer_list<T> ini ) :
m_numParams( ini.size() ) {
for ( auto&& e : ini ) {
m_vNodes.push_back( std::make_shared<T>( e ) );
}
}
}; // Nodes2
int main() {
int x = 3;
int y = 3;
int z = 3;
std::initialize_list<int> ini{ x, y, z };
Nodes2<int> nodes2( ini );
return 0;
}
如果您正在创建一个通用容器,并且不知道将要存储的对象类型 (T
),并且您希望允许移动构造,那么可变参数版本更好.
这是因为您无法从 std::initializer_list
移动,所以您的第二个版本将不得不复制构建 T
对象。
来自cppreference
:
An object of type
std::initializer_list<T>
is a lightweight proxy object that provides access to an array of objects of typeconst T
无法对存储的对象数组进行可变访问。