模板默认初始化,如果类中没有默认构造函数
Posted
技术标签:
【中文标题】模板默认初始化,如果类中没有默认构造函数【英文标题】:Template default init, if there no default constructor in a class 【发布时间】:2020-09-28 14:15:08 【问题描述】:我是 C++ 的新手。我写了一个函数模板来总结向量中的所有元素,如下所示:
template<typename T>
inline T sumator(const std::vector<T> &sequence)
T init = T;
return accumulate(sequence.begin(), sequence.end(), init);
在不声明默认构造函数之前一切正常,而是从例如 2 个参数声明构造函数。 像这样:
class A
private:
int a;
int b;
public:
// A() = default;
A(int aa, int bb) : a(aa),b(bb);
A operator+(const A &right) const
return a + right.a, b + right.b;
bool operator==(const A &right) const
return (a == right.a && b == right.b);
;
vector<A> bc = 3,5,5,5;
A res = Adder::sumator(works);
A result = 8,10;
assert(result,res);
现在我收到如下错误:错误:没有匹配的构造函数用于初始化“A” T 初始化 = T;
如何避免这种情况,不使用https://en.cppreference.com/w/cpp/types/is_default_constructible
UPD:我有很多类,其中一些具有默认构造函数,一些没有但具有用于 2 arg 的构造函数,一些用于 3,等等。而我要好好积累每一种情况
【问题讨论】:
评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:我能想到的可能解决方案。
-
通过提供初始值让用户依赖
std::accumulate
。
为sumator
提供一个带有初始值的重载。如果用户的类型没有默认构造函数,用户可以使用初始值调用重载。
坚持调用函数的类型有一个默认构造函数。
template<typename T>
inline T sumator(const std::vector<T> &sequence, T init)
return accumulate(sequence.begin(), sequence.end(), init);
template<typename T>
inline T sumator(const std::vector<T> &sequence)
return accumulate(sequence.begin(), sequence.end(), );
【讨论】:
谢谢,但请您解释一下第一个答案。也许我应该使用特征,否则对我没有帮助? @ВладимирКавиа 用户可以通过提供初始值直接使用std::accumulate
,不使用sumator
。
@ВладимирКавиа,这是个好问题。如果您无法在 SO 中找到答案,您可以在新帖子中提问。【参考方案2】:
您可以使用默认参数添加另一个参数。
template<typename T>
inline T sumator(const std::vector<T> &sequence, const T& init = T)
return accumulate(sequence.begin(), sequence.end(), init);
对于可以默认构造的类型,您仍然可以
sumator(some_vector);
并在T
不能默认构造时指定默认值。例如
sumator(some_vector, A0, 0);
【讨论】:
【参考方案3】:如果有人试图以错误的方式使用它,您可以将其拆分为两个重载并添加 static_assert
以提供很好的编译错误消息。
只有当类型是默认可构造的时,一个重载才有效,并且一个重载对于那些不是的类型有效:
#include <type_traits>
#include <vector>
template<typename T>
T sumator(const std::vector<T>& sequence)
static_assert(std::is_default_constructible_v<T>);
return std::accumulate(sequence.begin(), sequence.end(), T);
template<typename T>
T sumator(const std::vector<T>& sequence, const T& init)
return std::accumulate(sequence.begin(), sequence.end(), init);
另一种选择是添加一个默认参数,该参数可用于默认可构造的类型 - 您还可以使其更通用,使其不仅适用于vector
s,还适用于list
s 等。
template<template<class, class...> class C, class T, class... Ts>
T sumator(const C<T, Ts...>& sequence, const T& init = T)
return std::accumulate(sequence.begin(), sequence.end(), init);
【讨论】:
以上是关于模板默认初始化,如果类中没有默认构造函数的主要内容,如果未能解决你的问题,请参考以下文章