【问题标题】:C++11 way to write template for picking bigger integer type?C ++ 11编写模板以选择更大的整数类型的方法?
【发布时间】:2012-09-16 13:18:08
【问题描述】:

在 C++11 中编译时,在一个模板函数中,它接受 2 个模板参数,这两个模板参数都必须是无符号整数类型,我希望有一个局部变量具有两个模板参数中的任何一个的类型更多位。在 C++03 中,我可能会写如下内容:

template<bool, class T, class U>
struct pick_first;

template<class T, class U>
struct pick_first<true, T, U> {
    typedef T type;
};

template<class T, class U>
struct pick_first<false, T, U> {
    typedef U type;
};

template<class T, class U>
struct pick_bigger {
    typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type;
};

// usage
template<class uintX_t, class uintY_t>
void foo() {
    typename pick_bigger<uintX_t, uintY_t>::type mylocal = 0;
    // insert doing stuff with mylocal here
}

我可以利用任何新的 C++11 功能来简化此操作吗?我知道我可以使用可变参数模板使其不仅仅适用于成对的类型,而且我可以编写许多专门化来使其适用于新的 int_leastX_t 和 int_fastX_t 类型,而不是使用 pick_first。但我很好奇是否有一个更好的方法来解决这个问题。也许以某种方式利用 auto/constexpr/decltype?

【问题讨论】:

  • 你考虑过std::common_type
  • 我没有听说过 std::common_type!很有意思。这对我有用。不过,您应该将其发布为答案,以便我投票给您;)
  • @DavidRodríguez-dribeas 但由于整数提升规则,common_type 并不总是有效。例如,std::common_type&lt;short,char&gt;::typeint,它可能大于这两种类型中的任何一种。
  • pick_first 模板的名称似乎很恰当。
  • @Cheersandhth.-Alf:糟糕,已修复。

标签: c++ templates c++11 metaprogramming


【解决方案1】:

您的 pick_first 只是 C++11 中的 std::conditional,因此您可以编写

template<class T, class U>
struct wider {
    using type = typename std::conditional<sizeof(T) >= sizeof(U), T, U>::type; // I'm using the C++11 type alias feature 1) to educate people about them and 2) because I like them better than typedefs.
};

如果您只想要一个适合保存涉及两种类型的某些表达式的结果的类型,并且不一定需要这两种类型中的一种,那么std::common_type 或者auto 是最好的解决方案:

template<class uintX_t, class uintY_t>
void foo() {
    typename std::common_type<uintX_t, uintY_t>::type mylocal = 0;
    // insert doing stuff with mylocal here
}

// or
template<class uintX_t, class uintY_t>
void foo(uintX_t x, uintY_t y) {
    auto mylocal = x + y;
}

并且您的 pick_bigger 实现在其中缺少 typenametypedef typename pick_first&lt;(sizeof(T) &gt;= sizeof(U)), T, U&gt;::type type;

【讨论】:

  • 这增加了复杂的模板魔法,代码不能用最常用的编译器编译,以便为 OP 想要的类型的局部变量生成次优类型。这是非常愚蠢的。但它看起来确实很聪明。
  • 哇,我也不知道 std::conditional,亲爱的。
  • @JosephGarvin 您可以查看en.cppreference.com/w/cpp/types 以了解所有新的类型特征。
  • @bames53:是的,我刚刚读过那些。我没有意识到添加了任何在 tr1 时尚未提升的 type_traits,现在我将浏览所有部分,查看 C++11 标记的部分。
【解决方案2】:

这是我的解决方案,可以从 N 种类型中选择最宽的类型,直到模板递归限制。

我还包含了最窄的代码。

template <typename TFirst, typename... TOther>
struct widest {
private:
  using rhs_recursive_type = typename widest<TOther...>::type;

public:
  using type =
      typename std::conditional<sizeof(TFirst) >= sizeof(rhs_recursive_type),
                                TFirst, rhs_recursive_type>::type;
};

template <typename TFirst>
struct widest<TFirst> {
  using type = TFirst;
};

template <typename TFirst, typename... TOther>
struct narrowest {
private:
  using rhs_recursive_type = typename widest<TOther...>::type;

public:
  using type =
      typename std::conditional<sizeof(TFirst) <= sizeof(rhs_recursive_type),
                                TFirst, rhs_recursive_type>::type;
};

template <typename TFirst>
struct narrowest<TFirst> {
  using type = TFirst;
};

【讨论】:

    【解决方案3】:

    因为这两种类型都是无符号的,所以只需 decltype( T1() + T2() )

    【讨论】:

    • 这和common_type的整数提升有同样的问题,decltype(char()+short())是int。如果这是可以接受的,那么直接使用 common_type 是最好的解决方案。
    • @barnes54:common_type 添加了头依赖项。没有必要这样做。至于获取unsigned int 而不是short,OP 要求为局部变量提供合适的类型。最合适的类型是能够直接存储表达式结果而无需转换的类型。这就是这个表达式产生的。最合适的类型不是愚蠢的过度设计的模板化选择器产生的。
    • @downvoter:请解释您的反对意见。我知道,这个解释听起来是合理的,就像 barnes53 的三倍赞成评论一样,我什至可能不会对此发表评论(已经讨论过)。但只是为了完整性。
    猜你喜欢
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 1970-01-01
    • 2020-11-04
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多