C++ - перебор по кортежу и разрешению типа и постоянных параметров
В настоящее время я нахожусь в процессе написания арифметических перегрузок операторов для кортежей. Оператор выполняет итерации по кортежу для выполнения операции над каждым его отдельным элементом. Вот определение для оператора +=:
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return lhs;
}
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
std::get< I >(lhs) += std::get< I >(rhs);
return operator +=< Ts..., I + 1 >(lhs, rhs);
}
К сожалению, когда я пытаюсь вызвать оператора, GCC 4.6 не может решить, какую перегрузку он должен использовать. Например:
std::tuple< int, int, int, int > a = std::make_tuple(1, 2, 3, 4), b = std::make_tuple(5, 6, 7, 8);
a += b;
Выдает следующую ошибку:
:/Workspace/raster/main.cpp:833:7: instantiated from here
C:/Workspace/raster/main.cpp:809:45: error: no matching function for call to 'operator+=(std::tuple<int, int, int, int>&, const std::tuple<int, int, int, int>&)'
C:/Workspace/raster/main.cpp:809:45: note: candidates are:
C:/Workspace/raster/main.cpp:800:151: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I == sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
C:/Workspace/raster/main.cpp:806:83: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I != sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
Что странно, так как std::enable_if
условие должно отклонить неуместный вызов. На данный момент у меня есть следующий обходной путь, который фактически был моей предыдущей реализацией. Приведенная выше версия на самом деле является попыткой упрощения.
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return lhs;
}
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
std::get< I >(lhs) += std::get< I >(rhs);
return assignadd_impl< I + 1, Ts... >(lhs, rhs);
}
template< typename... Ts >
inline std::tuple< Ts... >& operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return assignadd_impl< 0, Ts... >(lhs, rhs);
}
Это компилируется и работает как ожидалось. Почему упрощенная версия отказывается от компиляции? Благодарю.
1 ответ
Использование явно заданных аргументов шаблона для шаблона функции или класса требует, чтобы любые пакеты параметров шаблона появлялись в конце общего списка параметров шаблона. перемещение Ts...
до конца списков параметров шаблона и изменение вызовов соответствующим образом заставляет код работать. Раздел 14.8.2.1 текущего проекта C++0x гласит, что пакеты параметров, которые не находятся в конце списка параметров шаблона, не могут быть выведены из вызова функции (что приводит к сбою исходного кода), но явно указывают весь шаблон аргументы operator+=
во всех случаях все еще вызывает ошибку SFINAE. Предыдущий вопрос имеет ссылку на точный текст, запрещающий это; В документации IBM говорится, что это тоже ошибка.