首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在两个不同的命名函数之间选择特性的替代方法是什么?

在两个不同的命名函数之间选择特性的替代方法是什么?
EN

Stack Overflow用户
提问于 2016-04-07 20:22:18
回答 2查看 183关注 0票数 4

还有..。我不想使用函数指针,我真的想直接使用函数本身(这样就可以内联或应用其他优化)。

假设:我有一个模板函数/类,它将计算一些数学内容,模板参数是整数类型,它可能是unsigned int32_t,也可能是unsigned int64_t

在某种程度上,我需要随机数,所以我需要一个生成器,在一种情况下,我将使用mt19937,在另一种情况下,使用mt19937_64。因此,实际的类型名称是不同的,但我必须选择一个,并在源代码中实际编写它。

显然,一个关于整型的特性类会工作得很好(这就是我现在要做的)。但在我看来,这一次使用的语法相当重,而且还有点非本地的(w.r.t )。阅读源代码,如果你明白我的意思)。

另一种方法是将生成器的使用封装在某些(泛型)函数中,并为我的两种完整类型提供它的全部专门化。这实际上是可以的。

但是:还有其他选择吗?这里是否有我可以使用的编译时"if“或"switch”(不完全是启用/禁用模板实例化的enable-if )?或者其他的东西(可能比模板元编程更简单,我只是没有看到)?

(P.S.请不要挂在mt19937 & mt19937_64上-我知道这两个别名都是我可以用整数类型实例化自己的类型)--但我更愿意使用标准定义和它们的一组相当神奇的数字。另外,我不仅对mt19937/mt19937_64感兴趣,还对其他类似的案例感兴趣。)

下面是我的特性类当前的代码:

代码语言:javascript
复制
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;
    ...
};
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-04-07 20:44:43

方法1:生成干净的分布式特征类型。

一些公用事业:

代码语言:javascript
复制
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;

现在,我们创建了标记重载,而不是特性类:

代码语言:javascript
复制
tag<std::mt1337> which_random_engine( tag_t<int> );
tag<std::mt1337_64> which_random_engine( tag_t<std::int64_t> );

让你做这样的过载..。哪里都行。

我们可以使用它来定义一个特性类:

代码语言:javascript
复制
template<class T>
using random_engine_for = type<decltype(which_random_engine(tag<T>))>;

使用:

代码语言:javascript
复制
random_engine_for<T> engine;

方法2:

代码语言:javascript
复制
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在语法上有更好的变化。

票数 4
EN

Stack Overflow用户

发布于 2016-04-07 20:45:09

你可以用std::conditional

代码语言:javascript
复制
template <class Int>
using engine_t = std::conditional_t<
    std::is_same<Int, uint32_t>{},
    std::mt19937,
    std::mt19937_64
>;

假设Int只能是uint32_tuint64_t。随着你最终得到的类型越多,这就会变得越来越复杂。此外,它还存在安全问题--如果现在支持uint16_t怎么办?您最终会默默地使用mt19937_64,这可能不是正确的决定。

您还可以使用mpl::map方法:

代码语言:javascript
复制
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;

这将更好地扩展到更多类型。如果引入一种新类型,这可能是一种更好的方法,这也是一个很难编译的错误。

我认为这是一个优先考虑的问题,并取决于你项目的其余部分。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36486443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档