c++ - 如何在 c++03 中获得模板参数的最精确表示?

标签 c++ templates c++11 c++03

下面的代码按预期工作(打印出 2.1):

#include <iostream>

template<typename T>
struct number {
  T n_;
  number(T n)
   : n_{n}
  {}
};

template<typename A, typename B>
auto operator+(number<A> a, number<B> b) -> number<decltype(a.n_+b.n_)> {
  return a.n_+b.n_;
}

int main() {
  number<int> a{1};
  number<double> b{1.1};
  number<double> c{a+b};
  std::cout << c.n_ << std::endl;
}

但是,它需要 C++11。假设我仅限于 C++03,是否有可能实现相同的行为? (即:使 operator+ 的返回类型使用成员 n_ 的最精确表示?)

最佳答案

您可以使用 Boost.TypeTraits:

template <typename A, typename B>
typename boost::common_type<A, B>::type operator+(number<A> a, number<B> b) {
  return a.n_ + b.n_;
}

或者根据 usual arithmetic conversions 的规则为此目的编写您自己的特征.我希望这个是令人满意的:

// 1. A and B undergo integral promotions.
// 2. If the rank of B is higher than A then they are swapped.
// 3. The result is A, if:
//     i. A or B or both are floating point, or
//     ii. A and B have the same signedness, or
//     iii. A is unsigned, or
//     iv. The size of A is greater than the size of B.
// 4. Otherwise, the result is make_unsigned<A>.

namespace detail {
    using namespace std::tr1;

    template <typename T> struct promote { typedef T type; };
    template <> struct promote<bool> { typedef int type; };
    template <> struct promote<char> { typedef int type; };
    template <> struct promote<signed char> { typedef int type; };
    template <> struct promote<unsigned char> { typedef int type; };
    template <> struct promote<short> { typedef int type; };
    template <> struct promote<unsigned short> { typedef int type; };

    template <typename> struct rank;
    template <> struct rank<int> { enum { value = 0 }; };
    template <> struct rank<unsigned> { enum { value = 0 }; };
    template <> struct rank<long> { enum { value = 1 }; };
    template <> struct rank<unsigned long> { enum { value = 1 }; };
    template <> struct rank<long long> { enum { value = 2 }; };
    template <> struct rank<unsigned long long> { enum { value = 2 }; };
    template <> struct rank<float> { enum { value = 3 }; };
    template <> struct rank<double> { enum { value = 4 }; };
    template <> struct rank<long double> { enum { value = 5 }; };

    template <typename> struct make_unsigned;
    template <> struct make_unsigned<int> { typedef unsigned type; };
    template <> struct make_unsigned<long> { typedef unsigned long type; };
    template <> struct make_unsigned<long long> { typedef unsigned long long type; };

    // 4.
    template < typename A
             , typename B
             , bool Is_floating_point_or_same_signs_or_A_is_unsigned_or_bigger >
    struct common_type_impl {
        typedef A type;
    };
    template <typename A, typename B>
    struct common_type_impl<A, B, false>
         : make_unsigned<A> {};

    // 3.
    template <typename A, typename B, bool A_is_higher>
    struct common_type_swap
         : common_type_impl< A
                           , B
                           , is_floating_point<A>::value || is_floating_point<B>::value
                             || (is_signed<A>::value == is_signed<B>::value)
                             || is_unsigned<A>::value || (sizeof(A) > sizeof(B))
                           > {};
    template <typename A, typename B>
    struct common_type_swap<A, B, false>
         : common_type_swap<B, A, true> {};

    // 2.
    template <typename A, typename B>
    struct common_type
         : common_type_swap<A, B, (rank<A>::value > rank<B>::value)> {};
}

// 1.
template <typename A, typename B>
struct common_type
     : detail::common_type< typename detail::promote<A>::type
                          , typename detail::promote<B>::type > {};

它至少比 Boost 的更具可读性。为简洁起见,它依赖于 is_floating_point , is_signed , 和 is_unsigned来自 TR1 , 但如果您不能使用 TR1,这些很容易自己实现。

DEMO

注意它不会给出与 std::common_type 相同的结果什么时候AB是同一类型,排名在int以下.这是设计使然。它给出与 decltype(A{} + B{}) 相同的结果.当我意识到这一点时,我应该给它起一个不同的名字,但我懒得理会。

关于c++ - 如何在 c++03 中获得模板参数的最精确表示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28986810/

相关文章:

c++ - 如何使模板函数头更短

c++ - 在 C/C++ 源代码中验证格式字符串的工具

javascript - 在 angularJS 1.x 中呈现 HTML

c++ - 使用 clang 优化进行编译时出现意外结果

c++ - 为什么这个可变参数函数调用不明确?

c++ - 将 Delphi 代码转换为 C++ 的最佳方法?

c++ - WinAPI:是否需要在可执行内存映射文件上调用 FlushInstructionCache?

c++ - 当我已经知道类型名称时嵌套模板参数

c++ - 将 lambda 传递给可变参数 std::function 时的类型推导

c++ - 在函数静态变量上调用 setter 一次