用于查找相似的连续类型名称的模板元程序
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>{})>
{ };
但是,这样一来,您就可以减轻或评估中的短路。
我是模板元编程的新手,正在尝试创建一个程序来查找参数包是否具有连续的相同类型名称。例如 <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
andstd::is_same_v
are available only starting from C++17 (but that you can usestd::integral_constant
andstd::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>{})>
{ };
但是,这样一来,您就可以减轻或评估中的短路。