将类型转换为整数的元函数,反之亦然
Metafunction to convert a type to an integer and vice-versa
typeid
允许在运行时为每个类型分配一个唯一的 std::type_index
。我想做同样的事情,静态地使用两个元函数:
// Get a unique integral number associated with the provided type
template <class T>
struct encode_type
{
using type = T;
static constexpr std::size_t value = /* Metaprogramming magic */;
};
// Get the type uniquely associated with the provided value
template <std::size_t V>
struct decode_type
{
static constexpr std::size_t value = V;
using type = /* Metaprogramming magic */;
};
有没有办法在 C++11 中做到这一点?
C++ 中的类型多于 size_t
。
作为证明:
template<size_t N> struct bob {};
bob<X>
类型与 size_t
值一样多。
template<class...> struct alice {};
现在,alice<bob<1>, bob<2>>
是一个有效的类型。 alice<alice<bob<1>>
.
也是
alice
类型比 bob
类型多得多。
因此没有从 size_t
值集到类型集的注入。
因此,如果是双射的,那么任何此类映射都必须是不完整的。您只能将某些类型的子集映射到 size_t
然后再映射回来。
您没有指定您只想处理类型的一个子集,所以答案是,您不能按照您的要求进行操作。
请注意,std::type_index
只是一个可散列的可比较对象。它不像整数值那样 "index"。
我将提供部分解决方案,因为我对解决所有混乱的细节不感兴趣。使用带有包含整个类型定义的参数的宏。现在用这个参数做三件事(需要有辅助宏):
- 按原样使用参数来定义类型。
- 将字符串化的参数传递给加密哈希函数。
- 该函数的输出将是某个位数的整数。毫无疑问,因为密码安全,该整数将大于内置整数类型。因此,不要使用
type_id
或 size_t
或诸如此类的东西,而是使用您自己的索引类型;它可以是一个 POD。
- 那个散列函数的值就是定义
encode_type
和decode_type
的神奇值。
- 由于模板参数中类型的限制,您可能必须使用
constexpr
存储哈希值的地址来定义decode_type
。
这里的基本原理与哥德尔不完备性定理证明中使用的相同,即一串字符总是有两种解释,一种是形式系统的成员,另一种是数字。 (顺便说一句,证明的核心是创造一种从正式系统内部谈论该数字的方式。)
可以肯定的是,使用 C++ 工具链中现成的工具的细节很混乱。不过,使之成为可能的关键因素是字符串化运算符 #
。这类似于上面的第二种解释,定义不是作为语言的成员,而是作为 "just data".
这是一个适用于 GCC 5.2 和 Clang 3.7 的可能解决方案。
我以后会用Filip Roséen's Constexpr Meta-Container with some slight alterations. As T.C. pointed out, this may be made ill-formed,所以这个方案在生产代码中完全不合理,但目前来说还是很酷的。我什至不确定这是否 100% 符合标准。
// This is our meta-container
using TypeMap = atch::meta_list<class A>;
// Get a unique integral number associated with the provided type
template <class T>
struct encode_type
{
using type = T;
// Push T into the container and store the pre-push size
//( requires slight change to Filip's code)
static constexpr std::size_t value = TypeMap::push<T>();
};
// Get the type uniquely associated with the provided value
template <std::size_t V>
struct decode_type
{
static constexpr std::size_t value = V;
// Get the type at index V
// (requires a small helper function addition)
using type = decltype(TypeMap::at<V>());
};
我对原代码的改动:
template<class T, class H = meta_list, std::size_t Size = counter::value()>
static constexpr std::size_t push (
size_type = push_state<
typename H::template value<>::template push<T>::result
> ()
) { return Size; }
我在 推送之前将 atch::meta_list::push
修改为 return 元容器的大小 。我使用了带有默认参数的模板参数来确保在推送之前计算大小。
template<size_type Idx, class H = meta_list>
static constexpr auto at () -> typename H::template value<>::template at<Idx>::result;
我在 atch::meta_list
中添加了一个小的 decltype
辅助函数,以隐藏所有相关的名称混乱。
一些测试代码:
int main () {
std::array<int, 4> encoded {
encode_type<int>::value,
encode_type<double>::value,
encode_type<std::string>::value,
encode_type<float>::value
};
std::cout << "Encoding: ";
for (auto i : encoded) std::cout << i << ", ";
std::cout << std::endl;
std::array<std::type_index, 4> decoded {
typeid(decode_type<0>::type),
typeid(decode_type<1>::type),
typeid(decode_type<2>::type),
typeid(decode_type<3>::type),
};
std::cout << "Decoding: ";
for (auto i : decoded) std::cout << i.name() << ", ";
std::cout << std::endl;
}
Clang 和 GCC 都会发出一堆警告,但它们都“有效”!
叮当声compiles, runs and outputs:
Encoding: 0, 1, 2, 3,
Decoding: i, d, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, f,
海湾合作委员会compiles, runs and outputs:
Encoding: 0, 1, 2, 3,
Decoding: i, d, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, f,
也许预处理步骤会更好...
typeid
允许在运行时为每个类型分配一个唯一的 std::type_index
。我想做同样的事情,静态地使用两个元函数:
// Get a unique integral number associated with the provided type
template <class T>
struct encode_type
{
using type = T;
static constexpr std::size_t value = /* Metaprogramming magic */;
};
// Get the type uniquely associated with the provided value
template <std::size_t V>
struct decode_type
{
static constexpr std::size_t value = V;
using type = /* Metaprogramming magic */;
};
有没有办法在 C++11 中做到这一点?
C++ 中的类型多于 size_t
。
作为证明:
template<size_t N> struct bob {};
bob<X>
类型与 size_t
值一样多。
template<class...> struct alice {};
现在,alice<bob<1>, bob<2>>
是一个有效的类型。 alice<alice<bob<1>>
.
alice
类型比 bob
类型多得多。
因此没有从 size_t
值集到类型集的注入。
因此,如果是双射的,那么任何此类映射都必须是不完整的。您只能将某些类型的子集映射到 size_t
然后再映射回来。
您没有指定您只想处理类型的一个子集,所以答案是,您不能按照您的要求进行操作。
请注意,std::type_index
只是一个可散列的可比较对象。它不像整数值那样 "index"。
我将提供部分解决方案,因为我对解决所有混乱的细节不感兴趣。使用带有包含整个类型定义的参数的宏。现在用这个参数做三件事(需要有辅助宏):
- 按原样使用参数来定义类型。
- 将字符串化的参数传递给加密哈希函数。
- 该函数的输出将是某个位数的整数。毫无疑问,因为密码安全,该整数将大于内置整数类型。因此,不要使用
type_id
或size_t
或诸如此类的东西,而是使用您自己的索引类型;它可以是一个 POD。
- 该函数的输出将是某个位数的整数。毫无疑问,因为密码安全,该整数将大于内置整数类型。因此,不要使用
- 那个散列函数的值就是定义
encode_type
和decode_type
的神奇值。- 由于模板参数中类型的限制,您可能必须使用
constexpr
存储哈希值的地址来定义decode_type
。
- 由于模板参数中类型的限制,您可能必须使用
这里的基本原理与哥德尔不完备性定理证明中使用的相同,即一串字符总是有两种解释,一种是形式系统的成员,另一种是数字。 (顺便说一句,证明的核心是创造一种从正式系统内部谈论该数字的方式。)
可以肯定的是,使用 C++ 工具链中现成的工具的细节很混乱。不过,使之成为可能的关键因素是字符串化运算符 #
。这类似于上面的第二种解释,定义不是作为语言的成员,而是作为 "just data".
这是一个适用于 GCC 5.2 和 Clang 3.7 的可能解决方案。
我以后会用Filip Roséen's Constexpr Meta-Container with some slight alterations. As T.C. pointed out, this may be made ill-formed,所以这个方案在生产代码中完全不合理,但目前来说还是很酷的。我什至不确定这是否 100% 符合标准。
// This is our meta-container
using TypeMap = atch::meta_list<class A>;
// Get a unique integral number associated with the provided type
template <class T>
struct encode_type
{
using type = T;
// Push T into the container and store the pre-push size
//( requires slight change to Filip's code)
static constexpr std::size_t value = TypeMap::push<T>();
};
// Get the type uniquely associated with the provided value
template <std::size_t V>
struct decode_type
{
static constexpr std::size_t value = V;
// Get the type at index V
// (requires a small helper function addition)
using type = decltype(TypeMap::at<V>());
};
我对原代码的改动:
template<class T, class H = meta_list, std::size_t Size = counter::value()>
static constexpr std::size_t push (
size_type = push_state<
typename H::template value<>::template push<T>::result
> ()
) { return Size; }
我在 推送之前将 atch::meta_list::push
修改为 return 元容器的大小 。我使用了带有默认参数的模板参数来确保在推送之前计算大小。
template<size_type Idx, class H = meta_list>
static constexpr auto at () -> typename H::template value<>::template at<Idx>::result;
我在 atch::meta_list
中添加了一个小的 decltype
辅助函数,以隐藏所有相关的名称混乱。
一些测试代码:
int main () {
std::array<int, 4> encoded {
encode_type<int>::value,
encode_type<double>::value,
encode_type<std::string>::value,
encode_type<float>::value
};
std::cout << "Encoding: ";
for (auto i : encoded) std::cout << i << ", ";
std::cout << std::endl;
std::array<std::type_index, 4> decoded {
typeid(decode_type<0>::type),
typeid(decode_type<1>::type),
typeid(decode_type<2>::type),
typeid(decode_type<3>::type),
};
std::cout << "Decoding: ";
for (auto i : decoded) std::cout << i.name() << ", ";
std::cout << std::endl;
}
Clang 和 GCC 都会发出一堆警告,但它们都“有效”!
叮当声compiles, runs and outputs:
Encoding: 0, 1, 2, 3,
Decoding: i, d, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, f,
海湾合作委员会compiles, runs and outputs:
Encoding: 0, 1, 2, 3,
Decoding: i, d, NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, f,
也许预处理步骤会更好...