简体   繁体   中英

Data members as lvalue-reference or rvalue-copies

Consider the following struct template:

template<typename T>
struct X
{
    X(T t) : t(std::forward<T>(t)) {}

    T t;
};

where T will either be a lvalue-reference (eg, const int& ) or a regular value (eg, int ). The idea is to use lvalue-reference whenever X is constructed from a lvalue , and a regular value when constructed from a rvalue .

Therefore, the following factory functions are defined to create an instance of X with such properties:

template<typename T>
X<const T&>
CreateX(const T& val)
{
    return X<const T&>(val);
}

template<typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, X<T>>::type
CreateX(T&& val)
{
    return X<T>(std::move(val));
}

So far, so good. If we now consider the struct template Y :

template<typename T, typename U>
struct Y
{
    Y(T t, U u) : t(std::forward<T>(t)), u(std::forward<T>(u)) {}

    T t;
    U u;
};

and we decide to make the same analogy as before for X , we end up with these four factory functions:

template<typename T, typename U>
Y<const T&, const U&>
CreateY(const T& t, const U& u)
{
    return Y<const T&, const T&>(t, u);
}

template<typename T, typename U>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, Y<T, const U&>>::type
CreateY(T&& t, const U& u)
{
    return Y<T, const U&>(std::forward<T>(t), u);
}

template<typename T, typename U>
typename std::enable_if<std::is_rvalue_reference<U&&>::value, Y<const T&, U>>::type
CreateY(const T& t, U&& u)
{
    return Y<const T&, U>(t, std::forward<T>(u));
}

template<typename T, typename U>
typename std::enable_if<std::is_rvalue_reference<T&&>::value and std::is_rvalue_reference<U&&>::value, Y<T, U>>::type
CreateY(T&& t, U&& u)
{
    return Y<T, U>(std::forward<T>(t), std::forward<T>(u));
}

Is there an alternative way to obtain the same result, perhaps less verbose? Fortunately my application will not require more than two template data members, but several other classes like Y will be needed, requiring four factory functions for each of them.

this results in non-const lvalue-references when constructed from lvalues, and I would like them to be const lvalue-references

You can write a simple trait that transforms the lvalue references:

template<class T>
struct transform_parameter{ using type = T; };

template<class T>
struct transform_parameter<T&>{ using type = T const&; };

template<class T>
using TransformParameter = typename transform_parameter<T>::type;

And apply that for all relevant template parameters:

template<class T>
X<TransformParameter<T>> make_X(T&& v){
  return {std::forward<T>(v)};
}

I also used a braced-init-list (aka uniform initialization) here to save me from writing the type twice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM