【问题标题】:how to implement smart templated type casting (e.g. C<int> / C<double> -> C<double>)如何实现智能模板类型转换(例如 C<int> / C<double> -> C<double>)
【发布时间】:2021-11-08 16:44:49
【问题描述】:

考虑以下代码:

template<typename T, typename U> 
constexpr auto divide(T rhs, U lhs) { return rhs / static_cast<T>(lhs); }

这里将默认值划分为 rhs 类型(这与我们从编译器获得的默认行为相同。

但是,如果我们想让除法更智能,这样它会在编译时推断出最好的返回类型(即不会导致任何参数变窄的类型)。

因此,divide(2, 3.0) 的结果是 0.6666...divide(2.0, 3) 也是如此,但 divide(2, 3) 的结果仍然是 0。

类似

template<typename T, typename U> 
constexpr auto divide2(T rhs, U lhs) { 
    if constexpr (is_same<U, double>::value)
        return static_cast<double>(rhs) / lhs;
    else
        return rhs / static_cast<T>(lhs); 
}

但更通用 - 我可以查看每种可能的类型,但有更好的方法吗?

是否有一些巧妙地使用概念或元编程方法来确定哪个是更广泛的类型并选择它作为转换类型?类似max_type(T, U)

【问题讨论】:

  • “这与我们从编译器获得的默认行为相同。” - 这是错误的。 en.cppreference.com/w/cpp/language/…
  • template&lt;typename T, typename U&gt; constexpr auto divide(T rhs, U lhs) { return rhs / lhs;} 似乎在这里完成了工作。 :)
  • @Jarod42 你是对的 :),我想简化我的问题,使其更具可读性,以至于它失去了意义......我正在使用类型包装器并返回一个类型包装器,在这种情况下我确实需要 common_type。

标签: c++ templates metaprogramming template-meta-programming


【解决方案1】:

我想你在找std::common_type:

#include <type_traits>
#include <iostream>

template<typename T> 
constexpr T divide_impl(T rhs, T lhs) { return rhs /lhs; }

template<typename T, typename U> 
constexpr auto divide(T rhs, U lhs) { return divide_impl<std::common_type_t<T,U>>(rhs,lhs); }


int main ()
{
    std::cout << std::is_same_v<int, decltype( divide(2,2))> << "\n";
    std::cout << std::is_same_v<double, decltype( divide(2.0,2))> << "\n";
}

输出是

1
1

因为divide(2,2) 返回一个intdivide(2.0,2) 返回一个double

Live Demo

但是,....

这里将默认值划分为 rhs 类型(这与我们从编译器获得的默认行为相同。

这是不对的。有关算术转换,请参见此处:https://en.cppreference.com/w/c/language/conversion。正如评论中提到的,实际上不需要演员表。以上仅在更一般的情况下有用,但对于rhs / lhs,您不会这样做。

【讨论】:

  • 是的,我把我的问题过于简单化了 :)
  • 或者,您可以decltype(std::declval&lt;T&gt;() / std::declval&lt;U&gt;())(rhs,lhs);
【解决方案2】:

使用common_type_tconstexpr

#include <type_traits>

template<typename type1_t, typename type2_t>
constexpr auto divide(const type1_t& value1, const type2_t& value2)
{
    using type_t = std::common_type_t<type1_t, type2_t>;
    return static_cast<type_t>(value1) / static_cast<type_t>(value2);
}


int main()
{
    static_assert(0.5 == divide(1.0, 2));
    static_assert(3ul == divide(10, 3ul));
    static_assert(0.5f == divide(1.0, 2.0f));
}

【讨论】:

  • using type_t = decltype(std::declval&lt;T&gt;() / std::declval&lt;U&gt;());
猜你喜欢
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 2018-01-02
相关资源
最近更新 更多