Некоторые проблемы, без определенного порядка
(1), как указано S.M., вы забыли typename
до T::value_type
template<typename B, typename T, typename... Ts> // .......................VVVVVVVV
constexpr std::enable_if_t<std::is_arithmetic_v<B> && std::is_arithmetic_v<typename T::value_type>, std::common_type_t<B, typename T::value_type>>
(2) вы забыли b
в рекурсивном вызове
// .........................V
return std::max(v, the_max2(b, ts...));
(3) вы использовали int
тип для v
, когда вы должны использовать auto
(или typename T::value_type
, если хотите)
// ...VVVV (not int)
const auto v = *std::max_element(t.cbegin(), t.cend());
(4) «общий тип» должен также оценивать Ts::value_type
, поэтому
// ...........................................VVVVVVVVVVVVVVVVVVVVVVVVVV
std::common_type_t<B, typename T::value_type, typename Ts::value_type...>
(5) вы должны явно указать тип для std::max()
.
using rt = std::common_type_t<B, typename T::value_type, typename Ts::value_type...>;
// ...
return std::max<rt>(v, the_max2(b, ts...));
// ............^^^^
(6) Я предлагаю получать аргументы в виде константных указателей вместо значений r
//..........VVVVVVV......VVVVVVV.......VVVVVVV
the_max2 (B const & b, T const & t, Ts const & ... ts)
Ниже приведен полный пример компиляции (с упрощением для обнаружения только один раз возвращенного общего типа)
#include <array>
#include <iostream>
#include <algorithm>
#include <type_traits>
template <typename B>
constexpr std::enable_if_t<std::is_arithmetic<B>::value, B>
the_max2 (B const & b)
{ return b; }
template <typename B, typename T, typename ... Ts,
typename RT = std::common_type_t<B, typename T::value_type,
typename Ts::value_type...>>
constexpr std::enable_if_t<std::is_arithmetic<B>::value
&& std::is_arithmetic<typename T::value_type>::value, RT>
the_max2 (B const & b, T const & t, Ts const & ... ts)
{
const auto v = *std::max_element(t.cbegin(), t.cend());
return std::max<RT>(v, the_max2(b, ts...));
}
int main()
{
constexpr std::array<short, 3> r1 {{1, 3, 5}};
constexpr std::array<int, 2> r2 {{3, 4}};
constexpr std::array<long, 4> r3 {{1, 2, 5, 6}};
constexpr std::array<long long, 2> r4 {{2, 6}};
auto m { the_max2(4l, r1, r2, r3, r4) };
std::cout << m << std::endl;
}
Предложение бонуса: если вы можете отказаться от теста std::is_arithmetic
, вам не нужна рекурсия, и вы можете написать свою функцию, просто расширив шаблон переменной следующим образом
template <typename B, typename ... Ts,
typename RT = std::common_type_t<B, typename Ts::value_type...>>
constexpr RT the_max3 (B const & b, Ts const & ... ts)
{ return std::max<RT>({b, *std::max_element(ts.cbegin(), ts.cend())...}); }
Если вы можете использовать C ++ 17 вместо C ++ 14, вы можете использовать свертывание шаблонов для восстановления теста std::is_arithmetic
SFINAE следующим образом
template <typename B, typename ... Ts,
typename RT = std::common_type_t<B, typename Ts::value_type...>>
constexpr std::enable_if_t<
(std::is_arithmetic<B>::value && ...
&& std::is_arithmetic<typename Ts::value_type>::value), RT>
the_max3 (B const & b, Ts const & ... ts)
{ return std::max<RT>({b, *std::max_element(ts.cbegin(), ts.cend())...}); }