Ваша проблема в том, что вы не сохраняете свои типы прямыми, а смешиваете и сопоставляете, предоставляя явные типы и делая вывод из шаблона. Если вы внимательно посмотрите на сообщение об ошибке, вы увидите, что происходит.
В случае enum вы звоните:
details.getValue<std::vector<E>>("");
Какие звонки:
template<typename T>
T getValue(const std::string& key)
{
return get_impl<T>(key, static_cast<T*>(0));
}
Здесь T
равно std::vector<E>
. Все идет нормально. Теперь перегрузка, которую вы хотите вызвать:
template<typename T>
typename std::enable_if<std::is_enum<T>::value, std::vector<T>>::type
get_impl(const std::string& key, std::vector<T>*) const
Но вы называете это get_impl<T>(...)
. Это означает, что при попытке разрешить эту перегрузку T
равен std::vector<E>
, а последний аргумент - std::vector<std::vector<E>>*
. Таким образом, этот шаблон функции просто не является кандидатом - последний аргумент не совпадает, и даже если он это сделал, std::vector<E>
не является перечислением, поэтому enable_if
исключит его.
<ч />
Способ исправить это - сохранить все в мире дедукций. И пока мы там, избегайте использования нулевых указателей для отправки тегов. Это сбивает с толку - потому что теперь некоторые части вашего кода используют указатели в качестве указателей, а некоторые просто используют их как типы. Мы можем просто сделать специальный тип для использования в качестве типа:
template <typename T> struct tag { };
И передать это в:
template <typename T>
T getValue(std::string const& key ) {
return get_impl(key, tag<T>{});
}
Обратите внимание, что я больше не указываю тип для get_impl
, это будет выведено. Теперь ваш случай перечисления:
template<typename T>
typename std::enable_if<std::is_enum<T>::value, std::vector<T>>::type
get_impl(const std::string& key, tag<std::vector<T>>) const
И это будет работать. Мы вывели бы T
как E
из параметра tag
, как вы и хотели, а E
- это перечисление, так что это работает.
Обратите внимание, что даже если вы используете C ++ 11, шаблоны псевдонимов работают. Поэтому, пока у вас нет доступа к std::enable_if_t
, вы все равно можете написать:
namespace xstd {
template <bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;
}
Что облегчает чтение всего этого:
template<typename T>
xstd::enable_if_t<std::is_enum<T>::value, std::vector<T>>
get_impl(const std::string& key, tag<std::vector<T>>) const