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

Template metaprogram to find similar consecutive typenames

本文关键字:连续 类型 相似 程序 查找      更新时间:2023-10-16

我是模板元编程的新手,曾试图创建一个程序,以查找参数包是否具有连续的相同类型名称。例如,<int, int><int, char, char>将返回true,而<int,char><int, char, int>将不返回true。

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

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_constantstd::is_same_v仅从C++17开始可用(但之前可以使用std::integral_constantstd::is_same<>::value(。

(c( @最大66

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而不是void调用sae_helper显然必须使用不同的类型。

我认为,当类型列表很长时,这种解决方案比递归解决方案更可取,因为要避免编译器模板的递归限制。

如果您可以使用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>{})>
{ };

但是,通过这种方式,您可以在评估中忽略短路。