还有..。我不想使用函数指针,我真的想直接使用函数本身(这样就可以内联或应用其他优化)。
假设:我有一个模板函数/类,它将计算一些数学内容,模板参数是整数类型,它可能是unsigned int32_t,也可能是unsigned int64_t。
在某种程度上,我需要随机数,所以我需要一个生成器,在一种情况下,我将使用mt19937,在另一种情况下,使用mt19937_64。因此,实际的类型名称是不同的,但我必须选择一个,并在源代码中实际编写它。
显然,一个关于整型的特性类会工作得很好(这就是我现在要做的)。但在我看来,这一次使用的语法相当重,而且还有点非本地的(w.r.t )。阅读源代码,如果你明白我的意思)。
另一种方法是将生成器的使用封装在某些(泛型)函数中,并为我的两种完整类型提供它的全部专门化。这实际上是可以的。
但是:还有其他选择吗?这里是否有我可以使用的编译时"if“或"switch”(不完全是启用/禁用模板实例化的enable-if )?或者其他的东西(可能比模板元编程更简单,我只是没有看到)?
(P.S.请不要挂在mt19937 & mt19937_64上-我知道这两个别名都是我可以用整数类型实例化自己的类型)--但我更愿意使用标准定义和它们的一组相当神奇的数字。另外,我不仅对mt19937/mt19937_64感兴趣,还对其他类似的案例感兴趣。)
下面是我的特性类当前的代码:
template <class Base>
struct traits { };
template <>
struct traits<unsigned __int32>
{
using base_t = unsigned __int32;
static const int nbits = std::numeric_limits<base_t>::digits;
using random_engine_t = std::mt19937;
...
};
template <>
struct traits<unsigned __int64>
{
using base_t = unsigned __int64;
static const int nbits = std::numeric_limits<base_t>::digits;
using random_engine_t = std::mt19937_64;
...
};发布于 2016-04-07 20:44:43
方法1:生成干净的分布式特征类型。
一些公用事业:
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag = {};
template<class Tag>using type=typename Tag::type;现在,我们创建了标记重载,而不是特性类:
tag<std::mt1337> which_random_engine( tag_t<int> );
tag<std::mt1337_64> which_random_engine( tag_t<std::int64_t> );让你做这样的过载..。哪里都行。
我们可以使用它来定义一个特性类:
template<class T>
using random_engine_for = type<decltype(which_random_engine(tag<T>))>;使用:
random_engine_for<T> engine;方法2:
template<class A, class B> struct zpair_t {};
template<class T, class...> struct lookup_t {};
template<class T, class A, class B, class...Ts>
struct lookup_t<T, zpair_t<A, B>, Ts...>:lookup_t<T, Ts...>{};
template<class T, class B, class...Ts>
struct lookup_t<T, zpair_t<T, B>, Ts...>:tag_t<B>{};
template<class T, class Default, class...Ts>
struct lookup_t<T, tag_t<Default>, Ts...>:tag_t<Default>{
static_assert(sizeof(Ts...)==0, "Default must be last");
};
template<class A, class B> using kv=zpair_t<A,B>;
template<class Default> using otherwise=tag_t<Default>;
template<class T, class...KVs>
using lookup = type<lookup_t<T, KVs...>>;
using random_engine_t =
lookup< T,
kv< int, std::mt19937 >,
kv< std::int64_t, std::mt19937_64 >,
otherwise<void> // optional
>;它使用一些相同的实用程序,并执行编译时类型映射。
我相信boost在语法上有更好的变化。
发布于 2016-04-07 20:45:09
你可以用std::conditional
template <class Int>
using engine_t = std::conditional_t<
std::is_same<Int, uint32_t>{},
std::mt19937,
std::mt19937_64
>;假设Int只能是uint32_t或uint64_t。随着你最终得到的类型越多,这就会变得越来越复杂。此外,它还存在安全问题--如果现在支持uint16_t怎么办?您最终会默默地使用mt19937_64,这可能不是正确的决定。
您还可以使用mpl::map方法:
using engine_map = mpl::map<
mpl::pair<uint32_t, std::mt19937>,
mpl::pair<uint64_t, std::mt19937_64>
>;
template <class Int>
using engine_t = typename mpl::at<engine_map, Int>::type;这将更好地扩展到更多类型。如果引入一种新类型,这可能是一种更好的方法,这也是一个很难编译的错误。
我认为这是一个优先考虑的问题,并取决于你项目的其余部分。
https://stackoverflow.com/questions/36486443
复制相似问题