如何找到具有默认值的可变数量的 constexpr std::arrays 的 constexpr max
How to find the constexpr max of variable number of constexpr std::arrays with a default value
因此,对于 N
的各种值,我有多个 constexpr std::array<int, N>
。在这种情况下:
constexpr std::array<int, 3> r1 {1, 3, 5};
constexpr std::array<int, 2> r2 {3, 4};
constexpr std::array<int, 4> r3 {1, 2, 5, 6};
constexpr std::array<int, 2> r4 {2, 6};
我想做的是在所有 array
中找到 constexpr
max
(随后是 min
)元素。这似乎工作得很好:
constexpr int the_max() {
return 0;
}
template<typename T, typename... Ts>
constexpr int the_max(T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
return std::max(v, the_max(ts...));
}
如图所示:
constexpr auto max_entry = dlx::the_max(r1, r2, r3);
std::cout << max_entry << '\n';
如预期的那样打印 6。
不过感觉这里应该有更多的逻辑,比如:
默认(或最小)值;和
跨std::array
的类型应该可以不同,只要都是算术类型即可。
我觉得这应该行得通:
template<typename B>
constexpr std::enable_if_t<std::is_arithmetic_v<B>, B>
the_max2(B&& b) {
return b;
}
template<typename B, typename T, typename... Ts>
constexpr std::enable_if_t<std::is_arithmetic_v<B> && std::is_arithmetic_v<T::value_type>, std::common_type_t<B, typename T::value_type>>
the_max2(B&& b, T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
return std::max(v, the_max2(ts...));
}
但结果是:
error: no matching function for call to 'the_max2<int>(int, const std::array<int, 3>&, const std::array<int, 2>&, const std::array<int, 4>&)'
并且只期望 1 个参数但收到 4 个参数,并且:
error: 'value_type' is not a member of 'const std::array<int, 3>&'
有人告诉我我做错了什么吗?任何帮助将不胜感激。
部分问题,排名不分先后
(1) 正如 S.M 指出的那样,您忘记了 T::value_type
之前的 typename
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) 当您应该使用 auto
(或 typename T::value_type
,如果您愿意)
时,您使用了 int
类型 v
// ...VVVV (not int)
const auto v = *std::max_element(t.cbegin(), t.cend());
(4) "common type" 也应该评估 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) 我建议接收参数作为常量指针而不是右值
//..........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())...}); }
您需要将 std::is_arithmetic
特性应用于传递参数的 value_type
而不是自身,您还需要从模板参数中删除引用,因为您正在使用转发引用。
使用c++14
namespace impl {
template <bool... Preds> struct all_dummy;
template <bool... Preds> using all = std::is_same<all_dummy<Preds...>, all_dummy<((void)Preds, true)...>>;
}
template<typename T, typename... Ts>
constexpr std::enable_if_t<
impl::all<
std::is_integral<typename std::remove_reference_t<T>::value_type>::value
>::value,
typename std::remove_reference_t<T>::value_type
>
the_max2(T&& t) {
const int v = *std::max_element(t.cbegin(), t.cend());
return v;
}
template<typename T, typename... Ts, typename R =
std::common_type_t<
typename std::remove_reference_t<T>::value_type,
typename std::remove_reference_t<Ts>::value_type...>
>
constexpr std::enable_if_t<
impl::all<
std::is_integral<typename std::remove_reference_t<T>::value_type>::value,
std::is_integral<typename std::remove_reference_t<Ts>::value_type>::value...
>::value,
R
>
the_max2(T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
return std::max<R>(v, the_max2(ts...));
}
如果 c++17 可用,可以使用 if constexpr
简化代码
namespace impl {
template <bool... Preds> struct all_dummy;
template <bool... Preds> using all = std::is_same<all_dummy<Preds...>, all_dummy<((void)Preds, true)...>>;
}
template<typename T, typename... Ts, typename R =
std::common_type_t<
typename std::remove_reference_t<T>::value_type,
typename std::remove_reference_t<Ts>::value_type...>
>
constexpr std::enable_if_t<
impl::all<
std::is_integral_v<typename std::remove_reference_t<T>::value_type>,
std::is_integral_v<typename std::remove_reference_t<Ts>::value_type>...
>::value,
R
>
the_max2(T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
if constexpr (sizeof...(ts) > 0) {
return std::max<R>(v, the_max2(ts...));
} else {
return v;
}
}
因此,对于 N
的各种值,我有多个 constexpr std::array<int, N>
。在这种情况下:
constexpr std::array<int, 3> r1 {1, 3, 5};
constexpr std::array<int, 2> r2 {3, 4};
constexpr std::array<int, 4> r3 {1, 2, 5, 6};
constexpr std::array<int, 2> r4 {2, 6};
我想做的是在所有 array
中找到 constexpr
max
(随后是 min
)元素。这似乎工作得很好:
constexpr int the_max() {
return 0;
}
template<typename T, typename... Ts>
constexpr int the_max(T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
return std::max(v, the_max(ts...));
}
如图所示:
constexpr auto max_entry = dlx::the_max(r1, r2, r3);
std::cout << max_entry << '\n';
如预期的那样打印 6。
不过感觉这里应该有更多的逻辑,比如:
默认(或最小)值;和
跨
std::array
的类型应该可以不同,只要都是算术类型即可。
我觉得这应该行得通:
template<typename B>
constexpr std::enable_if_t<std::is_arithmetic_v<B>, B>
the_max2(B&& b) {
return b;
}
template<typename B, typename T, typename... Ts>
constexpr std::enable_if_t<std::is_arithmetic_v<B> && std::is_arithmetic_v<T::value_type>, std::common_type_t<B, typename T::value_type>>
the_max2(B&& b, T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
return std::max(v, the_max2(ts...));
}
但结果是:
error: no matching function for call to 'the_max2<int>(int, const std::array<int, 3>&, const std::array<int, 2>&, const std::array<int, 4>&)'
并且只期望 1 个参数但收到 4 个参数,并且:
error: 'value_type' is not a member of 'const std::array<int, 3>&'
有人告诉我我做错了什么吗?任何帮助将不胜感激。
部分问题,排名不分先后
(1) 正如 S.M 指出的那样,您忘记了 T::value_type
typename
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) 当您应该使用 auto
(或 typename T::value_type
,如果您愿意)
int
类型 v
// ...VVVV (not int)
const auto v = *std::max_element(t.cbegin(), t.cend());
(4) "common type" 也应该评估 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) 我建议接收参数作为常量指针而不是右值
//..........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())...}); }
您需要将 std::is_arithmetic
特性应用于传递参数的 value_type
而不是自身,您还需要从模板参数中删除引用,因为您正在使用转发引用。
使用c++14
namespace impl {
template <bool... Preds> struct all_dummy;
template <bool... Preds> using all = std::is_same<all_dummy<Preds...>, all_dummy<((void)Preds, true)...>>;
}
template<typename T, typename... Ts>
constexpr std::enable_if_t<
impl::all<
std::is_integral<typename std::remove_reference_t<T>::value_type>::value
>::value,
typename std::remove_reference_t<T>::value_type
>
the_max2(T&& t) {
const int v = *std::max_element(t.cbegin(), t.cend());
return v;
}
template<typename T, typename... Ts, typename R =
std::common_type_t<
typename std::remove_reference_t<T>::value_type,
typename std::remove_reference_t<Ts>::value_type...>
>
constexpr std::enable_if_t<
impl::all<
std::is_integral<typename std::remove_reference_t<T>::value_type>::value,
std::is_integral<typename std::remove_reference_t<Ts>::value_type>::value...
>::value,
R
>
the_max2(T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
return std::max<R>(v, the_max2(ts...));
}
如果 c++17 可用,可以使用 if constexpr
namespace impl {
template <bool... Preds> struct all_dummy;
template <bool... Preds> using all = std::is_same<all_dummy<Preds...>, all_dummy<((void)Preds, true)...>>;
}
template<typename T, typename... Ts, typename R =
std::common_type_t<
typename std::remove_reference_t<T>::value_type,
typename std::remove_reference_t<Ts>::value_type...>
>
constexpr std::enable_if_t<
impl::all<
std::is_integral_v<typename std::remove_reference_t<T>::value_type>,
std::is_integral_v<typename std::remove_reference_t<Ts>::value_type>...
>::value,
R
>
the_max2(T&& t, Ts&&... ts) {
const int v = *std::max_element(t.cbegin(), t.cend());
if constexpr (sizeof...(ts) > 0) {
return std::max<R>(v, the_max2(ts...));
} else {
return v;
}
}