使用折叠表达式检查可变参数模板参数是否唯一

问题描述 投票:0回答:2

给定一个可变参数模板参数包,我想使用

inline constexpr bool
fold 表达式 检查赋予它的所有类型是否都是唯一的。我尝试过这样的事情:

template<class... T>
inline static constexpr bool is_unique = (... && (!is_one_of<T, ...>));

其中

is_one_of
是一个可以正确工作的类似布尔值。 但是无论我在 is_one_of 中放入什么内容,这一行都不会编译。这甚至可以使用折叠表达式来完成,还是我需要使用常规结构来实现此目的?

c++ templates c++17 variadic-templates fold-expression
2个回答
13
投票

您的方法实际上不起作用,因为

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>);

wandbox.org 上的实时示例

(感谢
Barry

使用折叠表达式进行简化。)


2
投票
--编辑--

谷歌搜索我发现了一个

有趣的解决方案

,它给了我灵感来避免递归并避免很多警告 因此您可以定义类型的包装器

template <typename> struct wrapT { };

以及从类型包装器继承的类型和整数包装器

template <typename T, std::size_t> struct wrapTI : public wrapT<T> { };

接下来,您可以定义一个 
foo

类,该类

递归
继承自 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...>

wrapT<T>
继承一次(且仅一次)时,
foo<Ts...>
才能转换为
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> ); }

© www.soinside.com 2019 - 2024. All rights reserved.