我有一个模板化函数,它接受许多元素,可能还需要参数化类型的初始值。如果未提供初始值,则假定此类型存在默认构造函数。 在这个函数中,我声明了给定数量的元素和分配给它们的初始值std::vector
。
只要模板类型不unique_ptr
就可以了:
#include <memory>
#include <vector>
using namespace std;
template <class T>
void define_vector(size_t size, const T& init_val=T())
{
vector<T> sample(100, init_val);
}
int main()
{
define_vector<int>(100); //<-- this works
define_vector<unique_ptr<int> >(100); //<-- this does not
return 0;
}
我知道它试图复制不允许unique_ptr
(删除构造函数(。但是有什么办法可以解决这个问题吗?
我当然可以定义 2 个版本的函数——一个带有参数,另一个没有初始值作为参数。但这是唯一的方法吗?
更新:澄清明显的误解。我知道使用非默认unique_ptr
时代码没有意义/不应该编译。我想到的是以下几点。假设有一个类Foo
只有显式构造函数,它将int
值作为参数。因此
define_vector<Foo>(100); //does not make sense and does not compile
define_vector<Foo>(100, Foo(42)); //makes sense and compiles.
然而:
//does not make sense and does not compile
define_vector<unique_ptr<int> > (100, std::make_unique<int>(42));
//does make sense but still does not compile
define_vector<unique_ptr<int> > (100);
那么是否有可能在不诉诸函数重载的情况下使上述第二种情况工作呢?
创建一个unique_ptr
数组是没有意义的,其中所有指针都具有相同的值(那么它们将不是唯一的(,除了值nullptr
。因此,接受任意初始值的函数对于unique_ptr
来说是无意义的。
我当然可以定义 2 个版本的函数——一个带有参数,另一个没有初始值作为参数。但这是唯一的方法吗?
这是一个简单的方法,所以这是一个好方法。这甚至可能是最简单的方法,我不会费心考虑是否有另一种方法。
我可以有一个函数可以接受初始值或使用默认构造函数(如果存在(
当您有 C++17 时,这是可能的:
template <class T>
void define_vector(size_t size, const T& init_val=T())
{
vector<T> sample;
if constexpr(is_copy_assignable<T>::value) {
sample.resize(size, init_val);
} else {
assert(init_val == T());
sample.resize(size);
}
}
问题是是否有更好的方法?
不,我不这么认为。上述情况不如重载,因为它允许传递初始参数,但它将被静默忽略,而重载方法在给定不可复制类型的第二个参数时会失败并出现错误。
使用可变参数模板,您可以执行以下操作:
template <typename T, typename ... Ts>
void define_vector(size_t size, const Ts&... init_val)
{
std::vector<T> sample(100, init_val...);
// ...
}
注意:如果需要,您可以将一些 SFINAE 添加到约束init_val
,以最多有一个参数。
然后
define_vector<int>(5); // Call vector<int>(5) instead of your vector<int>(5, 0)
define_vector<int>(5, 42); // Call vector<int>(5, 42);
define_vector<unique_ptr<int> >(5); // Call vector<unique_ptr<int>>(5)