使用折叠表达式检查可变参数模板参数是否唯一
Checking if variadic template parameters are unique using fold expressions
给定一个可变模板参数包,我想使用 inline constexpr bool
和 fold expressions 检查给它的所有类型是否都是唯一的。我尝试这样的事情:
template<class... T>
inline static constexpr bool is_unique = (... && (!is_one_of<T, ...>));
其中 is_one_of
是一个类似的布尔值,可以正常工作。
但是无论我在 is_one_of 中输入什么,这一行都不会编译。这甚至可以使用折叠表达式来完成,还是我需要为此目的使用常规结构?
您的方法实际上不起作用,因为 is_one_of
需要使用类型 T
和所有剩余类型 调用,不包括 T
.无法在单个参数包上使用 折叠表达式 来表达这一点。我建议改用专业化:
template <typename...>
inline constexpr auto is_unique = std::true_type{};
template <typename T, typename... Rest>
inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
>{};
用法:
static_assert(is_unique<>);
static_assert(is_unique<int>);
static_assert(is_unique<int, float, double>);
static_assert(!is_unique<int, float, double, int>);
(感谢 Barry 使用 折叠表达式 的简化。)
-- 编辑 --
谷歌搜索我发现了一个 给了我避免递归和避免大量警告的灵感
所以你可以定义一个
类型的包装器
template <typename>
struct wrapT
{ };
以及类型和整数的包装器,它继承自类型
的包装器
template <typename T, std::size_t>
struct wrapTI : public wrapT<T>
{ };
接下来你可以定义一个 foo
class 递归地 继承自 wrapTI
template <typename T,
typename = std::make_index_sequence<std::tuple_size<T>::value>>
struct foo;
template <typename ... Ts, std::size_t ... Is>
struct foo<std::tuple<Ts...>, std::index_sequence<Is...>>
: public wrapTI<Ts, Is>...
{ };
现在 is_unique
可以是
template <typename ... Ts>
static constexpr bool isUnique
= ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
重点是foo<Ts...>
只有在foo<Ts...>
从wrapT<T>
继承一次(且仅一次)的情况下才能转换为wrapT<T>
,即如果T
在 Ts...
.
中出现一次(且仅出现一次)
下面是一个完整的编译示例
#include <tuple>
#include <type_traits>
template <typename>
struct wrapT
{ };
template <typename T, std::size_t>
struct wrapTI : public wrapT<T>
{ };
template <typename T,
typename = std::make_index_sequence<std::tuple_size<T>::value>>
struct foo;
template <typename ... Ts, std::size_t ... Is>
struct foo<std::tuple<Ts...>, std::index_sequence<Is...>>
: public wrapTI<Ts, Is>...
{ };
template <typename ... Ts>
static constexpr bool isUnique
= ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
int main ()
{
static_assert( true == isUnique<int, long, long long> );
static_assert( false == isUnique<int, long, long long, int> );
}
给定一个可变模板参数包,我想使用 inline constexpr bool
和 fold expressions 检查给它的所有类型是否都是唯一的。我尝试这样的事情:
template<class... T>
inline static constexpr bool is_unique = (... && (!is_one_of<T, ...>));
其中 is_one_of
是一个类似的布尔值,可以正常工作。
但是无论我在 is_one_of 中输入什么,这一行都不会编译。这甚至可以使用折叠表达式来完成,还是我需要为此目的使用常规结构?
您的方法实际上不起作用,因为 is_one_of
需要使用类型 T
和所有剩余类型 调用,不包括 T
.无法在单个参数包上使用 折叠表达式 来表达这一点。我建议改用专业化:
template <typename...>
inline constexpr auto is_unique = std::true_type{};
template <typename T, typename... Rest>
inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
>{};
用法:
static_assert(is_unique<>);
static_assert(is_unique<int>);
static_assert(is_unique<int, float, double>);
static_assert(!is_unique<int, float, double, int>);
(感谢 Barry 使用 折叠表达式 的简化。)
-- 编辑 --
谷歌搜索我发现了一个
所以你可以定义一个
类型的包装器template <typename>
struct wrapT
{ };
以及类型和整数的包装器,它继承自类型
的包装器template <typename T, std::size_t>
struct wrapTI : public wrapT<T>
{ };
接下来你可以定义一个 foo
class 递归地 继承自 wrapTI
template <typename T,
typename = std::make_index_sequence<std::tuple_size<T>::value>>
struct foo;
template <typename ... Ts, std::size_t ... Is>
struct foo<std::tuple<Ts...>, std::index_sequence<Is...>>
: public wrapTI<Ts, Is>...
{ };
现在 is_unique
可以是
template <typename ... Ts>
static constexpr bool isUnique
= ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
重点是foo<Ts...>
只有在foo<Ts...>
从wrapT<T>
继承一次(且仅一次)的情况下才能转换为wrapT<T>
,即如果T
在 Ts...
.
下面是一个完整的编译示例
#include <tuple>
#include <type_traits>
template <typename>
struct wrapT
{ };
template <typename T, std::size_t>
struct wrapTI : public wrapT<T>
{ };
template <typename T,
typename = std::make_index_sequence<std::tuple_size<T>::value>>
struct foo;
template <typename ... Ts, std::size_t ... Is>
struct foo<std::tuple<Ts...>, std::index_sequence<Is...>>
: public wrapTI<Ts, Is>...
{ };
template <typename ... Ts>
static constexpr bool isUnique
= ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
int main ()
{
static_assert( true == isUnique<int, long, long long> );
static_assert( false == isUnique<int, long, long long, int> );
}