[英]How to initialize a class data member which is a std::set with custom comparator
[英]How to efficiently initialize a std::variant data member in a class template
考虑以下类模板,它可以使用std::variant
数据成员保存类型T
的值或某个ErrorInfo
类的实例:
template <typename T>
class ValueOrError
{
private:
std::variant<T, ErrorInfo> m_var;
};
如何有效地初始化变体T
替代方案?
我可以用这样的构造函数初始化它:
template <typename T>
class ValueOrError
{
public:
explicit ValueOrError(const T& val)
: m_var{val}
{
}
…
};
但是我可以使用什么语法/编码技术在初始化期间启用移动语义优化?
如果我定义一个采用T&&
的构造函数,我应该将参数std::move
还是std::forward
到m_var
?
template <typename T>
class ValueOrError
{
public:
// Efficient initialization with move semantics
explicit ValueOrError(T&& val)
: m_var{ /* ?? */ }
{
}
…
};
ValueOrError
模板还应该有一个构造函数重载,它接受一个ErrorInfo
并相应地初始化变量成员:
template <typename T>
class ValueOrError
{
public:
// Initialize with error code instead of T
explicit ValueOrError(const ErrorInfo& error)
: m_var{error}
{
}
…
};
通用T
构造函数重载与特定的ErrorInfo
重载正确交互非常重要。
ErrorInfo
是一个包含错误代码(例如简单整数)的小类,可以从这样的错误代码构造:
class ErrorInfo
{
public:
explicit ErrorInfo(int errorCode)
: m_errorCode{errorCode}
{
}
int ErrorCode() const
{
return m_errorCode;
}
// … other convenient methods
// (e.g. get an error message, etc.)
private:
int m_errorCode;
};
使用完美转发的 C++20 版本:
#include <concepts> // std::constructible_from
template <class T>
class ValueOrError {
public:
explicit ValueOrError(const ErrorInfo& error) : m_var{error} {}
template<class... Args>
requires std::constructible_from<T, Args...>
explicit ValueOrError(Args&&... val) :
m_var(std::in_place_type<T>, std::forward<Args>(val)...)
{}
private:
std::variant<T, ErrorInfo> m_var;
};
同样使用完美转发的 C++17 版本可能如下所示:
#include <type_traits> // std::is_constructible_v, std::enable_if_t
template <class T>
class ValueOrError {
public:
explicit ValueOrError(const ErrorInfo& error) : m_var{error} {}
template<class... Args,
std::enable_if_t<std::is_constructible_v<T, Args...>, int> = 0>
explicit ValueOrError(Args&&... val)
: m_var(std::in_place_type<T>, std::forward<Args>(val)...) {}
private:
std::variant<T, ErrorInfo> m_var;
};
示例用法:
class foo { // A non default constructible needing 3 constructor args
public:
foo(double X, double Y, double Z) : x(X), y(Y), z(Z) {}
private:
double x, y, z;
};
int main() {
ValueOrError<foo> voe1(1., 2., 3.); // supply all three arguments
// use the string constructor taking a `const char*`:
ValueOrError<std::string> voe2("Hello");
std::string y = "world";
// use the string constructor taking two iterators:
ValueOrError<std::string> voe3(y.begin(), y.end());
}
我会在 C++17 中这样做(使用“完美转发”+ SFINAE):
template <typename T>
class ValueOrError
{
public:
template<typename U>
explicit ValueOrError(U&& val, std::enable_if_t<std::is_constructible_v<T, U>>* = nullptr)
{
m_var.template emplace<T>(std::forward<U>(val));
}
private:
std::variant<T, ErrorInfo> m_var = ErrorInfo{0};
};
问题是应该如何使用与构造函数交互的错误?
或初始化列表版本:
template <typename T>
class ValueOrError {
public:
template <typename U>
explicit ValueOrError(U&& val, std::enable_if_t<std::is_constructible_v<T, U>>* = nullptr)
: m_var { std::in_place_type<T>, std::forward<U>(val) }
{
}
private:
std::variant<T, ErrorInfo> m_var;
};
我怀疑是否应该实施具有多个参数来构造T
的版本。 这是可能的,但 IMO 会使代码更难阅读。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.