编写值包装类的最佳方法

时间:2014-01-04 23:31:20

标签: c++ c++11

Supose我需要编写一个充当值的包装器的类:

template<typename T>
struct value_wrapper
{
    T value;

    value_wrapper( const T& v ) : value( v ) {}

    //etc...
};

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

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为左值?
  • 有没有标准方法来编写这种通用(右值和右值)别名?

2 个答案:

答案 0 :(得分:7)

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

#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)

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

答案 1 :(得分:1)

我认为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()以统一的方式访问存储的值)

Live example

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