专用于 std 元组的模板,而无需用户执行remove_cvref

Specializing a template for std tuple without requiring users to do remove_cvref

本文关键字:用户 执行 remove cvref std 用于 元组 专用      更新时间:2023-10-16

你可能知道,因为C++不支持类型列表,除非在特殊情况下,大多数人只是使用元组作为丑陋的类型列表。 因此,例如,要检查某些列表是否仅包含 fp 数字,可以这样做:

template <typename T>
struct AllFp {};
template <typename... T>
struct AllFp<std::tuple<T...>> {
static constexpr bool value =
(std::is_floating_point_v<std::remove_cvref_t<T>> && ...);
};

虽然这似乎有效,但如果用户传递 const std::tuple 或对元组的引用,它实际上不起作用。

#include<type_traits>
#include<tuple>
template <typename T>
struct AllFp {};
template <typename... T>
struct AllFp<std::tuple<T...>> {
static constexpr bool value =
(std::is_floating_point_v<std::remove_cvref_t<T>> && ...);
};
int main(){
static_assert(!AllFp<std::tuple<float, int, float>>::value);
static_assert(AllFp<std::tuple<float, long double, float>>::value);
// requires std::remove_cvref_t
//static_assert(AllFp<const std::tuple<float, long double, float>>::value);
//static_assert(AllFp<std::tuple<float, long double, float>&>::value);
}

有没有办法编写模板,以便"用户"(使用 AllFp 的人(不需要清理他们传递的元组类型?

注意:标记C++20,因为我对概念解决方案没问题。

使用 Boost.Mp11,这是一个简短的单行代码(一如既往(:

template <typename L>
using AllFp = mp_all_of<std::remove_cvref_t<L>, std::is_floating_point>;

请注意,std::remove_cvref_t实际上是C++20。对于早期标准,您可以只执行std::remove_cv_t<std::remove_reference_t<L>>或仅std::decay_t<L>以简洁起见。


使用更正的谓词:

template <typename T>
using decays_to_fp = std::is_floating_point<std::remove_cvref_t<T>>;
template <typename L>
using AllFp = mp_all_of<std::remove_cvref_t<L>, decays_to_fp>;    

或:

template <typename L>
using AllFp = mp_all_of_q<std::remove_cvref_t<L>,
mp_compose<std::remove_cvref_t, std::is_floating_point>>;

您所需要的只是额外的间接级别。将主模板和专用化从AllFp重命名为AllFp_Impl。然后AllFp创建一个别名模板,该模板负责从tuple本身中删除 cvref 限定:

template <typename T>
using AllFp = AllFp_Impl<std::remove_cvref_t<T>>;

这是一个演示。

您还可以使用一种自我继承。

我的意思是:您可以添加以下专业

template <typename T>
struct AllFp<T const> : public AllFp<T>
{ };
template <typename T>
struct AllFp<T&> : public AllFp<T>
{ };

下面是一个仅使用std::remove_cv_t的完整编译(static_assert()没有错误(示例

#include<type_traits>
#include<tuple>
template <typename T>
struct AllFp {};
template <typename T>
struct AllFp<T const> : public AllFp<T>
{ };
template <typename T>
struct AllFp<T&> : public AllFp<T>
{ };
template <typename... T>
struct AllFp<std::tuple<T...>> {
static constexpr bool value =
(std::is_floating_point_v<std::remove_cv_t<T>> && ...);
};
int main(){
static_assert(!AllFp<std::tuple<float, int, float>>::value);
static_assert(AllFp<std::tuple<float, long double, float>>::value);
static_assert(AllFp<const std::tuple<float, long double, float>>::value);
static_assert(AllFp<std::tuple<float, long double, float>&>::value);
}
相关文章: