2017-02-02 18 views
10

Я хотел бы получить тип возврата std::begin в общем виде. Мой текущий раствор:Получить возвращаемый тип начала на массиве c

using type = decltype(std::begin(std::declval<T>())); 

и он работает, когда T = std::vector<int>. Но я не понимаю, почему следующее не работает:

using type = decltype(std::begin(std::declval<int[3]>())); 

Я получаю ошибку:

example.cpp:83:60: error: no matching function for call to ‘begin(int [3])’ 
    using type = decltype(std::begin(std::declval<int[3]>())); 

Как получить тип возврата std::begin в общем виде?

ответ

7

Перегрузка для arrays является:

template< class T, std::size_t N > 
constexpr T* begin(T (&array)[N]); 

И std::declval<int[3]>() дает вам int(&&)[3], который не совпадает с перегрузкой. Он также не соответствует нормальной перегрузке контейнера, поскольку они являются SFINAE-ed при наличии c.begin(). Таким образом, у вас нет соответствующей функции.

Вам нужно вместо этого передать lvalue ссылку на массив на begin(), чтобы вернуть итератор. Так как вам нужно вручную обеспечить что Lvalue ссылку, когда вы используете псевдоним:

template <class T> 
using type = decltype(std::begin(std::declval<T>())); 

using arr = type<int(&)[3]>; // int* 

или иметь псевдоним сам предоставить ссылку Lvalue для вас:

template <class T> 
using type = decltype(std::begin(std::declval<T&>())); 

using arr = type<int[3]>; // int* 

Бывший кажется более правильным для меня , но YMMV.