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

时间:2017-11-27 12:50:13

标签: c++ templates c++17 variadic-templates fold-expression

给定一个可变参数模板参数包,我想使用myPopup.close(); fold expressions检查给定的所有类型是否唯一。我喜欢这样的事情:

inline constexpr bool

template<class... T> inline static constexpr bool is_unique = (... && (!is_one_of<T, ...>)); 是一个类似的bool,它可以正常工作。 但是,无论我将什么放入is_one_of,这条线都无法编译。这甚至可以使用折叠表达式来完成,还是我需要为此目的使用常规结构?

2 个答案:

答案 0 :(得分:10)

您的方法确实不起作用,因为需要使用is_one_of类型调用T,并且所有其余类型不包括T 。没有办法用单个参数包中的 fold表达式来表达它。我建议使用专业化:

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

live example on wandbox.org

(感谢Barry使用折叠表达式的简化。)

答案 1 :(得分:1)

- 编辑 -

谷歌搜索我发现interesting solution给了我灵感,以避免递归并避免大量警告

所以你可以定义一个

类型的包装器
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>,即TTs...中出现一次(且只有一次)。

以下是完整的编译示例

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