Способ решения вашей проблемы - добавить std::decay_t
к инструкции decltype
. От cppreference :
Применяет неявные преобразования lvalue-to-rvalue, array-to-pointer и function-to-pointer к типу T, удаляет cv-квалификаторы и определяет результирующий тип как тип typedef члена.
Что наиболее важно, он действует как идентификатор для типа, который не квалифицирован согласно какой-либо из приведенных выше аннотаций. Следовательно, можно написать
using T = typename std::decay_t<decltype(il)>::value_type;
для получения неквалифицированного value_type
, независимого от сигнатуры функции.
Теперь к другой части вашего вопроса, как написать это короче. Ну, в случае вашего примера можно сказать, что поскольку ваша лямбда ничего не захватывает, ее также можно заменить на бесплатный шаблон функции.
template < typename T >
void cref(std::initializer_list<T> const &il) {
/* use T and il */
}
или если он должен работать для любого контейнера
template < typename U >
void cref(U const &il) {
using T = typename U::value_type;
/* use T and il */
}
Очевидным преимуществом первого случая является то, что вы получаете доступ к T = value_type
«бесплатно». Другое преимущество (на мой взгляд) состоит в том, что вы получите гораздо более ясную ошибку компилятора, если случайно вызовете эту функцию с чем-то, что не является std::initializer_list<T>
. Вы можете исправить этот недостаток лямбды, добавив static_assert
, но это еще больше усугубит «недостаток», который вы изначально хотели найти.
Наконец, если вам действительно нравится лямбда-стиль написания функций или вам нужно что-то захватывать и вы не можете использовать подход свободных функций, вы можете рассмотреть возможность использования расширения GCC для лямбда-шаблонов:
auto cref_lambda = [] <typename U> (U const &il){
using T = typename U::value_type;
};
Это, наверное, самое короткое, что вы можете получить.