用于查找相似的连续类型名称的模板元程序

Template metaprogram to find similar consecutive typenames

我是模板元编程的新手,正在尝试创建一个程序来查找参数包是否具有连续的相同类型名称。例如 <int, int><int, char, char> 会 return 为真,而 <int,char><int, char, int> 不会。

我设法编写了这段代码,但它似乎在将参数包的每个值与其自身进行比较。我只是在寻找一种方法来遍历参数包的值以与其连续元素进行比较。

template<typename T, typename U>
struct sameTypename{
    enum {value = false};
};

template<typename T>
struct sameTypename<T, T>{
    enum {value = true};
};

template <typename T, typename ...args>
struct consTypename{
    enum {value = (sameTypename<consTypename<args...>, consTypename<args...>>::value)};
};

template <typename T>
struct consTypename<T, T>{
    enum {value = true};
};

template <typename T>
struct consTypename<T>{
    enum {value = false};
};

给你:

#include <type_traits>

template <typename ...P> struct has_adjacent_same_types : std::false_type {};
template <typename A, typename B, typename ...P> struct has_adjacent_same_types<A, B, P...>
    : std::bool_constant<std::is_same_v<A,B> || has_adjacent_same_types<B, P...>::value> {};

我用了 : std::false_type {};: std::bool_constant<X> {}; 而不是
{enum{value = false};};{enum{value = X};};,但这只是一个偏好问题。


我使用的一些特性来自 C++17。如果您使用的是旧版本,请注意:

std::bool_constant and std::is_same_v are available only starting from C++17 (but that you can use std::integral_constant and std::is_same<>::value before).

(c) @max66

HolyBlackCat 解决方案的变体。

template <typename ...>
struct has_adjacent_same_types : public std::false_type
 { };

template <typename T0, typename ... Ts>
struct has_adjacent_same_types<T0, T0, Ts...> : public std::true_type
 { };

template <typename T0, typename T1, typename ... Ts>
struct has_adjacent_same_types<T0, T1, Ts...>
   : public has_adjacent_same_types<T1, Ts...>
 { };

两个更简单的专业而不是一个更复杂的专业。

基本上是相同的东西(我想),但我觉得阅读和理解起来有点清晰。

我还提出了一个完全不同的解决方案,它使用模板折叠(不幸的是,只有 C++17 或更新版本)而不是模板递归。

template <typename...>
struct sae_helper;

template <typename ... Ts, typename ... Us>
struct sae_helper<std::tuple<Ts...>, std::tuple<Us...>>
   : public std::bool_constant<(std::is_same_v<Ts, Us> || ...)>
 { };

template <typename ... Ts>
struct some_adjacent_equal
   : public sae_helper<std::tuple<void, Ts...>, std::tuple<Ts..., void>>
 { };

如果 void 是要检查的类型列表中的可能类型,则从 some_adjacent_equal 调用 sae_helper 而不是 void 必须使用不同的类型,显然.

我认为当类型列表很长时,此解决方案优于递归解决方案,因为可以避免编译器模板递归限制。

如果可以使用 C++14,则可以使用 constexpr 函数而不是模板折叠(以及标记类型而不是 void),如下所示

template <typename ... Ts, typename ... Us>
constexpr bool sae_helper (std::tuple<Ts...> const &,
                           std::tuple<Us...> const &)
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { true, ret |= std::is_same<Ts, Us>::value... };

   return ret;
 }

struct no_type
 { };

template <typename ... Ts>
struct some_adjacent_equal
   : public std::integral_constant<bool, sae_helper(std::tuple<no_type, Ts...>{},
                                                    std::tuple<Ts..., no_type>{})>
 { };

但是,这样一来,您就可以减轻或评估中的短路。