std :: common_type的目的是什么?

时间:2011-06-28 08:37:27

标签: 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&); };
    

    推荐的解决方案是专门化common_type,这是繁琐的。有更好的解决方案吗?

供参考,参见N3242中的§20.9.7.6表57。

2 个答案:

答案 0 :(得分:26)

引入了

std::common_typestd::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将为您提供结果的类型。

答案 1 :(得分:1)

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

1。可变包装的 sum

这里a version for variadic sum需要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;
}

上面的示例是使用来自thisthis SO帖子的机制。


注意事项: :您可以使用the following code来达到相同的目的,而无需使用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)...);
}

2。要求可变参数包具有通用类型

Code below基于this SO post

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) {}

3。可变包装中的 make_array

有一个pending proposal for the function make_array。有关是否仍需要 make_array 的讨论,请参见this SO post

make_array的简单实现看起来像like this

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)...};
}

具有以下用法示例:

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");

请注意,make_array的提案可以选择提供实际请求的类型,但是如果未提供,则将使用common_type