Рассмотрят следующий шаблон структуры:члены данных как именующая-ссылка или RValue-копий
template<typename T>
struct X
{
X(T t) : t(std::forward<T>(t)) {}
T t;
};
где Т будет либо именующей-ссылка (например, const int&
) или регулярное значение (например, int
). Идея состоит в том, чтобы использовать lvalue-reference всякий раз, когда X
построен из lvalue и имеет постоянное значение при построении от rvalue.
Таким образом, следующие фабричные функции определены для создания экземпляра X
с такими свойствами:
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));
}
До сих пор, так хорошо. Если мы теперь рассмотрим шаблон структуры 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;
};
, и мы решили сделать такую же аналогию, как и раньше для X
, мы в конечном итоге эти четыре заводских функций:
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));
}
Есть альтернативный способ для получения того же результата, возможно, менее многословного? К счастью, моему приложению не потребуется более двух элементов данных шаблона, но потребуются несколько других классов, таких как Y
, требующих четырех заводских функций для каждого из них.
'шаблон Х make_X (Т && v) {возвращение Х {станд :: вперед (v)}; } ', нет глупых SFINAE. Это работает как для lvalues, так и для rvalues. Я бы сменил конструктор на 'T &&', поэтому у вас нет ненужного перехода от ctor-параметра к члену. –
Xeo
Благодаря @Xeo, но это приводит к неконстантным lvalue-ссылкам при построении из lvalues, и я хотел бы, чтобы они были константными ссылками lvalue. Я согласен с использованием 'T &&', чтобы избежать дополнительного перемещения. – Allan
Затем сделайте просто свойство, которое преобразует 'T &' -> 'T const &'. Не должно быть трудно. – Xeo