将 std::type_identity 对象转换为类型
Converting std::type_identity object to a type
假设我们创建两个 type_of
函数 return std::type_identity
, like:
template<auto VAR>
auto type_of() {
return std::type_identity<decltype(VAR)>{};
}
template<typename T>
auto type_of() {
return std::type_identity<T>{};
}
从std::type_identity
获取实际类型的方法似乎有点麻烦:
// this works
// both i1 and i2 are ints
decltype(type_of<int>())::type i1;
decltype(type_of<int{}>())::type i2;
有没有办法在上面的表达式中放弃 decltype
的需要,或者把它放在一个可重用的表达式中,以获得更好的效果,比如:
// can this work?
type_of<int>()::type i1;
type_of<int{}>()::type i2;
甚至更好:
// can this work??
type_of_t<int> i1;
type_of_t<int{}> i2;
注意:类型和非类型模板参数的特化,这可能是一个方向,不起作用(无法编译):
template<auto>
struct type_of;
template<typename T>
struct type_of<T> { // <== compilation error: type/value mismatch
using type = T;
};
template<auto VAR>
struct type_of<VAR> {
using type = decltype(VAR);
};
您可以创建类型别名。但是你不能“超载”它。所以我的解决方案是创建两个:
template <auto Var>
using type_of_var_t = decltype(type_of<Var>())::type;
template <class T>
using type_of_t = decltype(type_of<T>())::type;
auto test()
{
type_of_var_t<11> i1 = 24;
type_of_t<int> i2 = 17;
}
从 std::type_identity
对象获取类型 can be encapsulated into the following expresion:
template<auto x>
using type = typename decltype(x)::type;
这将允许替换繁琐的表达式:
decltype(type_of<int>())::type i1;
decltype(type_of<int{}>())::type i2;
用更简单的表达方式:
type<type_of<int>()> i1;
type<type_of<int{}>()> i2;
还是需要经过两步(type_of
然后type
)作为第一步应该能够得到一个 type 或 variable,它只适用于函数模板重载,那么函数不能 return类型,因此它 return 是一个需要模板表达式来提取内部类型的对象。
根据您要对类型执行的操作,代码可以变得更加简单。
如果您只想创建该类型的对象,您可以将对象的创建转发到函数中:
template<auto VAR, typename... Args>
auto create_type_of(Args&&... args) {
return decltype(VAR){std::forward<Args>(args)...};
}
template<typename T, typename... Args>
auto create_type_of(Args&&... args) {
return T{std::forward<Args>(args)...};
}
auto i1 = create_type_of<int>(7);
auto i2 = create_type_of<int{}>(7);
以这种方式从 std::type_identity
can work 创建类型的一般情况:
template<auto VAR>
constexpr auto type_of() {
return std::type_identity<decltype(VAR)>{};
}
template<typename T>
constexpr auto type_of() {
return std::type_identity<T>{};
}
template<typename T, typename... Args>
auto create(std::type_identity<T>, Args&&... args) {
return T{std::forward<Args>(args)...};
}
auto i1 = create(type_of<int>(), 7);
auto i2 = create(type_of<int{}>(), 7);
请注意,整个过程仅适用于可用作 non-type 模板参数的变量。有关更通用的方法,无需模板(但使用宏......),因此可以用于不能作为模板参数的变量,请参阅
在 C++ 中,模板参数必须是值、类型或另一个模板(它本身必须适合声明的模板头)。一定是其中之一。
如果你想这样做:
the idea is to get something that is unaware on the caller side whether the template parameter is a type or a variable
能够做到这一点的基本要求是编写一个模板,其参数可以是值或类型。
C++ 不允许这样做。
模板函数重载允许您摆脱类似的东西。但这之所以有效,是因为它不是一个模板。这是 两个 模板超载。选择哪一个取决于提供的模板参数。
模板类 不能重载。并且模板专业化不能改变原始模板的性质(比如它的模板参数是什么)。它只能让你重新解释原来的模板参数的模板参数,以便提供一个替代的实现。
如果你想要这个,你将不得不等到 C++ 能够拥有一个可以是任何东西的模板参数,或者直到 C++ 能够将类型转换为值并返回(即:反射).
根据设计,C++ 模板中的模板参数是模板、类型或值。
在模板中,您知道它们是什么。模板中依赖于模板参数的所有表达式都使用 typename
或 template
关键字(或上下文)消除歧义,因此在替换参数之前知道它们的类别。
现在有元编程库可以与 value-substitutes 一起使用 3.
template<class T> struct type_tag_t {using type=T;};
template<class T> constexpr type_tag_t<T> tag={};
template<template<class...>class Z> struct template_z_t {
template<class...Ts>
using result = Z<Ts...>;
template<class...Ts>
constexpr result<Ts...> operator()( type_tag_t<Ts>... ) const { return {}; }
};
template<template<class...>class Z>
constexpr template_z_t<Z> template_z = {};
此处模板映射到 constexpr 函数对象。 template_z
模板可让您将 type-templates 映射到此域。
template<auto x>
using type = typename decltype(x)::type;
template<auto x>
constexpr std::integral_constant<std::decay_t<decltype(x)>, x> k = {};
所以,
constexpr auto vector_z = template_z<std::vector>;
constexpr auto vector_tag = vector_z( tag<int>, tag<std::allocator<int>> );
然后你可以回到类型:
type<vector_tag> v{1,2,3,4};
这可能不是您想要的。
您可能愿意查看 Universal Template Parameters
的提案
蕴含的示例与您同时专攻 TTP 和 NTTP 的用例非常匹配:
template <template auto>
struct X;
template <typename T>
struct X<T> {
// T is a type
using type = T;
};
template <auto val>
struct X<val> : std::integral_constant<decltype(val), val> {
// val is an NTTP
};
假设我们创建两个 type_of
函数 return std::type_identity
, like:
template<auto VAR>
auto type_of() {
return std::type_identity<decltype(VAR)>{};
}
template<typename T>
auto type_of() {
return std::type_identity<T>{};
}
从std::type_identity
获取实际类型的方法似乎有点麻烦:
// this works
// both i1 and i2 are ints
decltype(type_of<int>())::type i1;
decltype(type_of<int{}>())::type i2;
有没有办法在上面的表达式中放弃 decltype
的需要,或者把它放在一个可重用的表达式中,以获得更好的效果,比如:
// can this work?
type_of<int>()::type i1;
type_of<int{}>()::type i2;
甚至更好:
// can this work??
type_of_t<int> i1;
type_of_t<int{}> i2;
注意:类型和非类型模板参数的特化,这可能是一个方向,不起作用(无法编译):
template<auto>
struct type_of;
template<typename T>
struct type_of<T> { // <== compilation error: type/value mismatch
using type = T;
};
template<auto VAR>
struct type_of<VAR> {
using type = decltype(VAR);
};
您可以创建类型别名。但是你不能“超载”它。所以我的解决方案是创建两个:
template <auto Var>
using type_of_var_t = decltype(type_of<Var>())::type;
template <class T>
using type_of_t = decltype(type_of<T>())::type;
auto test()
{
type_of_var_t<11> i1 = 24;
type_of_t<int> i2 = 17;
}
从 std::type_identity
对象获取类型 can be encapsulated into the following expresion:
template<auto x>
using type = typename decltype(x)::type;
这将允许替换繁琐的表达式:
decltype(type_of<int>())::type i1;
decltype(type_of<int{}>())::type i2;
用更简单的表达方式:
type<type_of<int>()> i1;
type<type_of<int{}>()> i2;
还是需要经过两步(type_of
然后type
)作为第一步应该能够得到一个 type 或 variable,它只适用于函数模板重载,那么函数不能 return类型,因此它 return 是一个需要模板表达式来提取内部类型的对象。
根据您要对类型执行的操作,代码可以变得更加简单。
如果您只想创建该类型的对象,您可以将对象的创建转发到函数中:
template<auto VAR, typename... Args>
auto create_type_of(Args&&... args) {
return decltype(VAR){std::forward<Args>(args)...};
}
template<typename T, typename... Args>
auto create_type_of(Args&&... args) {
return T{std::forward<Args>(args)...};
}
auto i1 = create_type_of<int>(7);
auto i2 = create_type_of<int{}>(7);
以这种方式从 std::type_identity
can work 创建类型的一般情况:
template<auto VAR>
constexpr auto type_of() {
return std::type_identity<decltype(VAR)>{};
}
template<typename T>
constexpr auto type_of() {
return std::type_identity<T>{};
}
template<typename T, typename... Args>
auto create(std::type_identity<T>, Args&&... args) {
return T{std::forward<Args>(args)...};
}
auto i1 = create(type_of<int>(), 7);
auto i2 = create(type_of<int{}>(), 7);
请注意,整个过程仅适用于可用作 non-type 模板参数的变量。有关更通用的方法,无需模板(但使用宏......),因此可以用于不能作为模板参数的变量,请参阅
在 C++ 中,模板参数必须是值、类型或另一个模板(它本身必须适合声明的模板头)。一定是其中之一。
如果你想这样做:
the idea is to get something that is unaware on the caller side whether the template parameter is a type or a variable
能够做到这一点的基本要求是编写一个模板,其参数可以是值或类型。
C++ 不允许这样做。
模板函数重载允许您摆脱类似的东西。但这之所以有效,是因为它不是一个模板。这是 两个 模板超载。选择哪一个取决于提供的模板参数。
模板类 不能重载。并且模板专业化不能改变原始模板的性质(比如它的模板参数是什么)。它只能让你重新解释原来的模板参数的模板参数,以便提供一个替代的实现。
如果你想要这个,你将不得不等到 C++ 能够拥有一个可以是任何东西的模板参数,或者直到 C++ 能够将类型转换为值并返回(即:反射).
根据设计,C++ 模板中的模板参数是模板、类型或值。
在模板中,您知道它们是什么。模板中依赖于模板参数的所有表达式都使用 typename
或 template
关键字(或上下文)消除歧义,因此在替换参数之前知道它们的类别。
现在有元编程库可以与 value-substitutes 一起使用 3.
template<class T> struct type_tag_t {using type=T;};
template<class T> constexpr type_tag_t<T> tag={};
template<template<class...>class Z> struct template_z_t {
template<class...Ts>
using result = Z<Ts...>;
template<class...Ts>
constexpr result<Ts...> operator()( type_tag_t<Ts>... ) const { return {}; }
};
template<template<class...>class Z>
constexpr template_z_t<Z> template_z = {};
此处模板映射到 constexpr 函数对象。 template_z
模板可让您将 type-templates 映射到此域。
template<auto x>
using type = typename decltype(x)::type;
template<auto x>
constexpr std::integral_constant<std::decay_t<decltype(x)>, x> k = {};
所以,
constexpr auto vector_z = template_z<std::vector>;
constexpr auto vector_tag = vector_z( tag<int>, tag<std::allocator<int>> );
然后你可以回到类型:
type<vector_tag> v{1,2,3,4};
这可能不是您想要的。
您可能愿意查看 Universal Template Parameters
的提案蕴含的示例与您同时专攻 TTP 和 NTTP 的用例非常匹配:
template <template auto>
struct X;
template <typename T>
struct X<T> {
// T is a type
using type = T;
};
template <auto val>
struct X<val> : std::integral_constant<decltype(val), val> {
// val is an NTTP
};