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.