编写值包装类的最佳方式

Best way to write a value wrapper class

本文关键字:最佳 方式 包装类      更新时间:2023-10-16

Supose我需要编写一个类,作为值的包装器:

template<typename T>
struct value_wrapper
{
T value;
value_wrapper( const T& v ) : value( v ) {}
//etc...
};

该类被设计为用作原始值的别名,因此,如果该值是右值,则包装器将保存该值,如果它是左值,则封装器将保存对它的引用。该类应该重载比较运算符,并以这种方式使用:

template<typename T , typename U>
bool f( const T& lhs , const T& rhs )
{
return wrapper( lhs ) == wrapper( rhs );
}

或者这个:

int main()
{
int a , b;
bool flag = wrapper( a ) == wrapper( b ) || wrapper( a ) == wrapper( 2 );
}

我的问题是:实现这种事情的最佳(有效)方式是什么这个问题似乎很宽泛,我的意思是:

  • 如何将成员value?定义为左值的T&,以及右值的T
  • 有没有标准的方法来编写这种通用(右值和左值)别名

我只需提供合适的转换运算符:

#include <utility>
#include <type_traits>
template <typename T> struct Wrapper
{
static_assert(!std::is_reference<T>::value, "Do not use a reference type");
using type = T;
T value;
Wrapper(T && t) : value(std::move(t)) {}
Wrapper(T const & t) : value(t) {}
operator T const & () const noexcept { return value; }
operator T       & ()     & noexcept { return value; }
operator T      && ()    && noexcept { return std::move(value); }
// maybe some more CV variants...
};
template <typename U> struct Wrapper<U &>
{
using type = U &;
U & ref;
Wrapper(U & u) : ref(u) {}
operator U & () { return ref; }
};

我会附带一个推导函数:

template <typename T> Wrapper<T> wrap(T && t)
{ return Wrapper<T>(std::forward<T>(t)); }

示例用法:

int n = 10;
bool b = wrap(n) == wrap(5 + 5)

转换运算符允许您使用在基础类型上定义的任何运算符。

我认为Kerrek SB通过提供专业化(很久以前就获得了+1)走在了正确的轨道上,因此每个案例都得到了最有效的处理。

问题是,你不能只添加隐式转换运算符,如果你想提供自己的运算符重载,事情可能会变得相当棘手。

我提出的解决方案试图通过将某个变量的大小写信息放入布尔模板参数来处理这个问题。以下是value_wrapper类的基本框架:

template< typename T, bool >
class value_wrapper
{
private:
T t_; // store a value
public:
explicit value_wrapper( T&& t ) : t_( std::move( t ) ) {}
const T& cref() const { return t_; }
};
template< typename T >
struct value_wrapper< T, true > // specialization for lvalue references
{
private:
const T& t_; // store a reference
public:
explicit value_wrapper( const T& t ) : t_( t ) {}
const T& cref() const { return t_; }
};

棘手的部分是包装值的方便方法:

// needs a better name and needs to be moved into a "detail" or "impl" namespace
template< typename T >
using helper = value_wrapper< typename std::decay< T >::type, 
std::is_lvalue_reference< T >::value >;
template< typename T >
helper< T > wrap( T&& t )
{
return helper< T >( std::forward< T >( t ) );
}

这样一来,value_wrapper的第一个模板参数总是衰减类型,这使得现在一切都变得更容易:

template< typename T, bool BL, bool BR >
bool operator==( const value_wrapper< T, BL >& lhs, const value_wrapper< T, BR >& rhs )
{
return lhs.cref() == rhs.cref();
}

(显然,您希望以不同的方式实现它们,但您始终可以通过cref()以统一的方式访问存储的值)

实时示例

如果你需要非恒定访问等,你可能需要调整它,但我希望以上内容能让你开始。如果您需要更多帮助/想法,请随时询问:)