实现可变类型特征 简介 < >我寻找模式将C++类型特征转换为它们的强>变量对应项< /强>。采用方法来解决问题将受到赞赏,而自动化任务的生成性编程模式将是理想的选择 例子
采取以下行动:实现可变类型特征 简介 < >我寻找模式将C++类型特征转换为它们的强>变量对应项< /强>。采用方法来解决问题将受到赞赏,而自动化任务的生成性编程模式将是理想的选择 例子,c++,templates,c++11,template-meta-programming,generative-programming,C++,Templates,C++11,Template Meta Programming,Generative Programming,采取以下行动: std::is_same<T, U>::value; enable_if -> enable_if_any // enable if any clause is true enable_if_all // enalbe if all clauses are true enable_for // enable only for the type provided 因此,eg是相
std::is_same<T, U>::value;
enable_if -> enable_if_any // enable if any clause is true
enable_if_all // enalbe if all clauses are true
enable_for // enable only for the type provided
因此,eg是相同的
问题:
上一篇封面概述与
- 主要类型类别
- 复合类型类别
- 类型属性
- 支持的操作
我将如何概括类型特征如下所示:
std::is_same<T, U>::value;
enable_if -> enable_if_any // enable if any clause is true
enable_if_all // enalbe if all clauses are true
enable_for // enable only for the type provided
上面的存在相同的
示例过于简单化。有没有正确实施的想法
有些类型特征“返回”修改过的类型。对于将这些扩展到任意数量类型的实现,有什么建议吗
是否存在类型_特征,使其不可扩展到任意数量的类型参数 我不完全理解您希望实现的具体目标,但以下帮助可能很有用,从bool\u sequence
开始:
#include <type_traits>
// Note: std::integer_sequence is C++14,
// but it's easy to use your own version (even stripped down)
// for the following purpose:
template< bool... Bs >
using bool_sequence = std::integer_sequence< bool, Bs... >;
// Alternatively, not using C++14:
template< bool... > struct bool_sequence {};
#包括
//注:std::integer_序列是C++14,
//但使用自己的版本很容易(即使是精简版)
//为下列目的:
模板
使用bool_序列=std::integer_序列;
//或者,不使用C++14:
模板结构布尔_序列{};
接下来,您可以检查是否所有或任何布尔值或设置为:
template< bool... Bs >
using bool_and = std::is_same< bool_sequence< Bs... >,
bool_sequence< ( Bs || true )... > >;
template< bool... Bs >
using bool_or = std::integral_constant< bool, !bool_and< !Bs... >::value >;
模板
使用bool_和=std::是否相同,
布尔|u序列<(Bs | |真)…>>;
模板
使用bool_或=std::integral_常量::价值>;
它们作为构建更高级、更专业的特征的积木而派上用场。例如,您可以这样使用它们:
typename< typename R, bool... Bs > // note: R first, no default :(
using enable_if_any = std::enable_if< bool_or< Bs... >::value, R >;
typename< typename R, bool... Bs > // note: R first, no default :(
using enable_if_all = std::enable_if< bool_and< Bs... >::value, R >;
typename< typename T, typename... Ts >
using are_same = bool_and< std::is_same< T, Ts >::value... >;
typename//注意:R优先,无默认值:(
使用enable_if_any=std::enable_if::value,R>;
typename//注意:R优先,无默认值:(
使用enable_if_all=std::enable_if::value,R>;
typename
使用are_same=bool_和::value…>;
您还可以使用,以实现启用所有和启用任何:
#include <type_traits>
#include <iostream>
#include <initializer_list>
#include <string>
namespace detail
{
template <typename... Conds>
struct and_ : std::true_type {};
template <typename... Conds>
struct or_ : std::false_type {};
template <typename Cond, typename... Conds>
struct and_<Cond, Conds...>
: std::conditional<Cond::value, detail::and_<Conds...>, std::false_type>::type {};
template <typename Cond, typename... Conds>
struct or_<Cond, Conds...>
: std::conditional<Cond::value, std::true_type, detail::and_<Conds...>>::type {};
}
template <typename... T>
using are_all_pod = detail::and_<std::is_pod<T>...>;
template <typename... T>
using any_is_pod = detail::or_<std::is_pod<T>...>;
template <typename... Args, typename = typename std::enable_if<are_all_pod<Args...>::value>::type>
void f(Args... args)
{
(void)std::initializer_list<int>{(std::cout << args << '\n' , 0)...};
}
template <typename... Args, typename = typename std::enable_if<any_is_pod<Args...>::value>::type>
void g(Args... args)
{
(void)std::initializer_list<int>{(std::cout << args << '\n' , 0)...};
}
int main()
{
std::string s = "hello"; // non pod
//f(1, 1.2, s); // this will fail because not all types are pod
g(1, 1.2, s); // this compiles because there is at least one pod in argument pack
}
#包括
#包括
#包括
#包括
名称空间详细信息
{
模板
结构和类型:std::true\u类型{};
模板
结构或:std::false\u类型{};
模板
结构和_
:std::conditional::type{};
模板
结构或_
:std::conditional::type{};
}
模板
使用are\u all\u pod=detail::and;
模板
使用任意_is_pod=detail::or_u;
模板
无效f(参数…参数)
{
(void)std::initializer_list{(std::cout受Daniel Fray回答中的优秀思想启发,我们甚至可以扩展这些可变特征的范围。使用元组,我们可以将特征应用于可变类型包的集合,而不是“仅”将可变类型包与参考类型进行比较
例如,我们将能够看到类型int,int,int,float
是否与int,int,int,float
的类型相同(确实如此!)
为此,我们需要以下结构:
- 元组和产生元组尾部的方法
- 通过向布尔序列追加(或预加)布尔值来扩展布尔序列的一种方法
太长,读不下去了
我在这篇文章中编译了几个例子
定义变量特征设施
首先,我们提供了一个助手,用于将布尔序列一次扩展一个值:
template <bool ... Bs>
struct bool_sequence {};
template <bool b, typename T>
struct prepend_bool_seq;
template <bool b, bool ... bs>
struct prepend_bool_seq<b, bool_sequence<bs...>> {
typedef bool_sequence<b, bs...> type;
};
此模板以自底向上的方式递归计算trait应用程序给定的bool序列。现在,随着生成的bool序列的提供,我们可以使用上面定义的helpers对结果执行逻辑操作
接下来,一些助手可以为任何二进制(或一元)类型特征重现are_same
示例的逻辑:
// Helper templates for common type traits (unary and binary)
template <template <typename> class UnaryTrait, typename ... Ts>
using apply_unary_trait = details::apply_trait<UnaryTrait, std::tuple<Ts...>>;
template <template <typename, typename> class BinaryTrait, typename Ref, typename ... Ts>
using apply_binary_trait = details::apply_trait<BinaryTrait,
std::tuple<decltype(std::declval<Ts>(), std::declval<Ref>())...>,
std::tuple<Ts...>>;
template <template <typename, typename> class BinaryTrait, typename Ref, typename ... Ts>
using apply_binary_trait_ref_last = details::apply_trait<BinaryTrait,
std::tuple<Ts...>,
std::tuple<decltype(std::declval<Ts>(), std::declval<Ref>())...>>;
我们还可以在列表上应用traits逻辑。例如,给定两个类型列表,我们可能希望检查第一个列表中的类型是否可转换为第二个列表中的匹配类型:
// int is convertible to long and char const* is convertible to std::string
std::cout << all_of<details::apply_trait<std::is_convertible,
std::tuple<int, char const*>,
std::tuple<long, std::string>::type>::value;
//int可转换为long,char const*可转换为std::string
std::cout用于“返回多个类型”:您只能返回一个顶级类型。要返回类型列表,通常使用std::tuple
。这样的东西让我想要模板
等价于使用
--模板使用for_all=templateUniv;
,像for_all
,它可以让您轻松通过模板e
生成到其他元编程中而不显得丑陋。Univ是一个非常有用的工具。我想知道您是否可以提供Exist
@0x499602D2布尔逻辑的实现:bool\u或=!bool\u和
-这回答了您的问题吗?否则,请更具体地说明实现的哪个部分导致了您的问题麻烦。+1bool|u序列<(Bs | | true)
是最方便的片段。@Solkar我会被(Bs,true)
吸引。不管怎样,我喜欢它具有恒定的递归深度!@Yakk(Bs,true)
会在某些编译器上引起警告,这就是我使用(Bs | | true)的原因它是一个模板,每一组(不同的)参数生成一种不同的类型,这就是std::is__same
所需要的。
template <typename T>
struct all_of;
template <bool ... Bs>
struct all_of<bool_sequence<Bs...>> :
public std::is_same<bool_sequence<true, Bs...>, bool_sequence<Bs..., true>> {};
template <typename T>
struct any_of;
template <bool ... Bs>
struct any_of<bool_sequence<Bs...>> :
public std::integral_constant<bool, !all_of<bool_sequence<!Bs...>>::value> {};
namespace details {
// Sentinel type to detect empty tuple tails
struct null_type {};
template <typename T>
struct tuple_tail;
template <typename T>
struct tuple_tail<std::tuple<T>> {
typedef null_type type;
};
template <typename T, typename ... Ts>
struct tuple_tail<std::tuple<T, Ts...>> {
typedef std::tuple<Ts...> type;
};
}
namespace details {
template <template <typename...> class Trait, typename ... Tuples>
struct apply_trait {
static constexpr bool atomic_value =
Trait<typename std::tuple_element<0u, Tuples>::type...>::value;
typedef typename prepend_bool_seq<atomic_value,
typename apply_trait<Trait,
typename tuple_tail<Tuples>::type...>::type>::type type;
};
template <template <typename...> class Trait, typename ... Tuples>
struct apply_trait<Trait, null_type, Tuples...> {
typedef bool_sequence<> type;
};
}
// Helper templates for common type traits (unary and binary)
template <template <typename> class UnaryTrait, typename ... Ts>
using apply_unary_trait = details::apply_trait<UnaryTrait, std::tuple<Ts...>>;
template <template <typename, typename> class BinaryTrait, typename Ref, typename ... Ts>
using apply_binary_trait = details::apply_trait<BinaryTrait,
std::tuple<decltype(std::declval<Ts>(), std::declval<Ref>())...>,
std::tuple<Ts...>>;
template <template <typename, typename> class BinaryTrait, typename Ref, typename ... Ts>
using apply_binary_trait_ref_last = details::apply_trait<BinaryTrait,
std::tuple<Ts...>,
std::tuple<decltype(std::declval<Ts>(), std::declval<Ref>())...>>;
template <typename Ref, typename ... Ts>
using are_same = all_of<typename apply_binary_trait<std::is_same, Ref, Ts...>::type>;
// int is convertible to long and char const* is convertible to std::string
std::cout << all_of<details::apply_trait<std::is_convertible,
std::tuple<int, char const*>,
std::tuple<long, std::string>::type>::value;