为什么std :: array的演绎指南不允许使用不同的类型?

Dan*_*ica 6 c++ arrays templates template-argument-deduction c++17

扣除指南std::array要求所有类型都相同:

std::array arr = { 1, 2, 3.4 }; // error
Run Code Online (Sandbox Code Playgroud)

这种要求背后的理由是什么?如果允许使用不同的类型,是否会有任何重大缺陷?例如:

namespace std {
   template <typename... T>
   array(T...) -> array<std::common_type_t<T...>, sizeof...(T)>;
}

std::array arr = { 1, 2, 3.4 }; // decltype(arr)::value_type deduced as double
Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 10

大量的设计问题使用common_type.例如std::common_type_t<A, B, C>,std::common_type_t<C, A, B>std::common_type_t<C, B, A>不必都存在-如果他们这样做,不必是相同的类型:

struct A;
struct B;
struct C;
struct A { operator B(); };
struct B { operator C(); };
struct C { operator A(); };

static_assert(std::is_same_v<std::common_type_t<A, B, C>, C>);
static_assert(std::is_same_v<std::common_type_t<C, A, B>, B>);
static_assert(std::is_same_v<std::common_type_t<C, B, A>, A>);
Run Code Online (Sandbox Code Playgroud)

当重新排序初始化程序的元素导致推断出不同的类型(或发出错误)时,这会产生"有趣的"用户体验.


Cal*_*eth 6

它与函数模板参数的推导方式相匹配.

如果它们产生多于一个可能的推导A,则类型推断失败.

[temp.deduct.call]/5

例如

template<typename T>
void foo(T, T){}

template<typename T>
struct bar{ bar(T, T) {} };

int main()
{
    foo(1, 1.5); // error, note:   deduced conflicting types for parameter 'T' ('int' and 'double')
    bar(1, 1.5); // error, note:   deduced conflicting types for parameter 'T' ('int' and 'double')
}
Run Code Online (Sandbox Code Playgroud)

但是您可以提供常见类型的演绎指南.

template<typename T>
struct baz{ baz(T, T) {} };

template<typename T, typename U>
baz(T, U) -> baz<std::common_type_t<T, U>>    
Run Code Online (Sandbox Code Playgroud)

或重载转发到常见类型

template<typename T>
void quux(T, T){}

template<typename T, typename U>
std::enable_if_t<!std::is_same<std::decay_t<T>, std::decay_t<U>>> quux(T t, U u) 
{ 
    using C = std::common_type_t<T, U>; 
    quux<C>(std::forward<C>(t), std::forward<C>(u)); // I think this is right
}

int main()
{
    baz(1, 1.5);
    quux(1, 1.5);
}
Run Code Online (Sandbox Code Playgroud)