std::get
уже делает именно то, что вы хотите, поэтому ваша цель — просто написать псевдоним для существующей функции. Хитрость заключается в том, чтобы усовершенствовать ваш аргумент и возвращаемое значение, чтобы ничего не было потеряно. Например :
#include <tuple>
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
return std::get<0>(std::forward<T>(p_tuple));
}
int main()
{
std::tuple<int, int> mutable_x = { 42, 24 };
const std::tuple<int, int> const_x = { 10, 20 };
// mutable_ref is a `int&`
auto&& mutable_ref = getFirstElem(mutable_x);
// const_ref is a `const int&`
auto&& const_ref = getFirstElem(const_x);
}
decltype(auto)
убедитесь, что возвращаемое значение идеально перенаправлено. Это сохраняет квалификатор ссылки и константность возвращаемого типа. Использование auto
приведет к уменьшению возвращаемого значения до базового типа значения (в данном случае int
). auto&&
аналогичным образом используется для захвата результата без отбрасывания квалификатора ссылки или константы.
Изменить. Кажется, в вопросе, который я пропустил, был компонент безопасности типов. Это легко исправить, введя static_assert
и std::is_same
для сравнения типа аргумента с ожидаемым типом. Важно удалить ссылочные квалификаторы и модификаторы cv, чтобы обеспечить правильность сравнения.
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
using t_expected = std::tuple<int, int>;
// Verify that the tuple matches the expectations
using t_tuple_clean = std::remove_cv_t<std::remove_reference_t<T>>;
static_assert(std::is_same<t_expected, t_tuple_clean>::value, "Unexpected tuple type");
return std::get<0>(std::forward<T>(p_tuple));
}
К сожалению, сообщение об ошибке обычно будет довольно длинным. К сожалению, я не вижу способа написать это, где можно было бы использовать встроенное в компилятор сопоставление аргументов (что генерировало бы более четкие сообщения об ошибках). Для идеальной пересылки требуется, чтобы аргумент был шаблонным типом. В противном случае вам понадобятся две перегрузки (одна для константных и одна для неконстантных аргументов), которые нарушат однофункциональное требование вопроса.
Если вас утомляет выписывание проверки для каждой функции, вы можете написать вспомогательную функцию, которую можно использовать для упрощения написания новых функций доступа.
#include <tuple>
#include <type_traits>
template<size_t index, class t_expected, class t_tuple>
decltype(auto) getHelper(t_tuple&& p_tuple)
{
// Verify that the tuple matches the expectations
using t_tuple_clean = std::remove_cv_t<std::remove_reference_t<t_tuple>>;
static_assert(std::is_same<t_expected, t_tuple_clean>::value, "Unexpected tuple type");
// Forward to std::get
return std::get<index>(std::forward<t_tuple>(p_tuple));
}
template<class T>
decltype(auto) getFirstElem(T&& p_tuple)
{
return getHelper<0, std::tuple<int, int>>(std::forward<T>(p_tuple));
}
Функция доступа теперь завершится с ошибкой компилятора, если будет предоставлен неправильный тип кортежа:
int main()
{
// Compiler error 'Unexpected tuple type'
std::tuple<double, int> bad_tuple{};
auto&& bad_ref = getFirstElem(bad_tuple);
}
person
François Andrieux
schedule
10.07.2018
const&
. - person NathanOliver   schedule 10.07.2018