std :: common_type的目的是什么?

pmr*_*pmr 20 c++ c++11

我开始关注std::common_type并且不确定它的用途和功能.有些事情让我觉得奇怪:

  • 争论的顺序很重要:common_type<Foo, Bar, Baz>可能与之不同common_type<Baz, Foo, Bar>.要么可以编译,要么可能没有.虽然从common_type定义的方式来看这很清楚,但它感觉奇怪且不直观.这是因为缺乏通用解决方案还是打算?
  • 实例化可能导致编译器错误,而不是我可以处理的事情.如何检查是否common_type实际编译?可能是专门的is_convertible还不够common_type
  • 在这样的情况下仍然无法找出常见类型:

    struct Baz;
    struct Bar { int m; };
    struct Foo { int m; }; 
    struct Baz { Baz(const Bar&); Baz(const Foo&); };
    
    Run Code Online (Sandbox Code Playgroud)

    建议的解决方案是专业化common_type,这是繁琐的.有更好的解决方案吗?

有关参考,请参见N3242中的§20.9.7.6表57.

Ant*_*ams 28

std::common_type被引入用于std::duration---如果你添加一个std::duration<int>和一个std::duration<short>然后结果应该是std::duration<int>.不是指定允许配对的源源不断,而是决定委托一个单独的模板,该模板使用适用于?:arithmetic-if运算符的核心语言规则来找到结果.

然后人们看到这个模板通常很有用,它被添加为std::common_type,并扩展为处理任意数量的类型.在C++ 0x库中,它仅用于成对的类型.

您应该能够使用新的SFINAE规则来检测某些实例化std::common_type是否有效.我没试过.在大多数情况下,如果没有"普通类型",那么无论如何都没有任何有意义的事情,因此编译错误是合理的.

std::common_type不是魔术 - 它遵循规则?:.如果true?a:b要编译,std::common_type<decltype(a),decltype(b)>::type会给你结果的类型.

  • Upvoted.我将补充:`common_type`更像是库构建器的工具,而不是库用户的工具.只有当库作者在其库的界面中设计了`common_type`时,库用户通常才使用`common_type`.库作者可以选择是否使用`common_type`,这取决于`common_type`是否对他的库有用. (2认同)

Ami*_*rsh 6

以下是 的一些用例std::common_type

1.可变参数包的总和

这是需要的可变参数总和的版本common_type

template<typename... T>
constexpr auto sum(T&&... values) {
    std::common_type_t<T...> sum {}; // <= here we need std::common_type
    // see code in the link above for the machinery of the below code
    static_for<sizeof...(T)>([&](auto index) {
        sum += get<index>(values...);
    });
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

上面的例子是使用这个这个SO帖子中的机器。


注意:您可以使用以下代码实现相同的目的,而无需common_type

template<typename T>
auto sum(T&& t) {
    return t;
}

template<typename T, typename... Ts>
auto sum(T&& t, Ts&&... ts) {
    return t + sum(std::forward<Ts>(ts)...);
}
Run Code Online (Sandbox Code Playgroud)

2.要求变量包有一个通用类型

下面的代码基于此 SO 帖子

template <typename AlwaysVoid, typename... Ts>
struct has_common_type_impl : std::false_type {};

template <typename... Ts>
struct has_common_type_impl<std::void_t<std::common_type_t<Ts...>>, Ts...>
    : std::true_type {};

template <typename... Ts>
concept has_common_type = 
    sizeof...(Ts) < 2 ||
    has_common_type_impl<void, Ts...>::value;

template<typename... Ts> requires has_common_type<Ts...>
void foo(Ts&&... ts) {}
Run Code Online (Sandbox Code Playgroud)

3.可变参数包中的make_array

对于函数make_array有一个悬而未决的提案。有关是否仍需要make_array的讨论,请参阅此 SO 帖子

一个简单的实现如下make_array所示:

template<typename... T>
constexpr auto make_array(T&&... values) requires has_common_type<T...> {
    using TYPE = std::common_type_t<std::decay_t<T>...>;
    return std::array<TYPE, sizeof...(T)>{static_cast<TYPE>(values)...};
}
Run Code Online (Sandbox Code Playgroud)

具有以下用法示例:

constexpr auto arr1 = make_array(1, 2, 3);
constexpr auto arr2 = make_array(1, 2.5, 3);
using namespace std::string_literals;
auto arr3 = make_array("hello"s, "world");
Run Code Online (Sandbox Code Playgroud)

请注意,提案make_array有一个选项来提供实际请求的类型,但如果未提供,则将common_type使用该类型。