std :: make_array公共类型

时间:2017-04-15 03:40:33

标签: c++ c++17

std::make_array使用通用类型。但是,我的主要问题是它允许代码编译,否则将无法编译:

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

int main()
{
    auto arr = std::experimental::make_array(1, 3.0); // Compiles
    foo(1, 3.0); // a and b types must match
    std::array<int, 2> arr2{1, 3.0}; // narrowing conversion
}

这不一定是坏事。但我发现它不一致。请注意,由于模板参数推导的工作方式,std::make_array<int>实际上禁用推导(因为您明确指定了类型),因此无法解决问题。

这里使用普通类型的理由是什么?

2 个答案:

答案 0 :(得分:1)

  

std::make_array使用常见类型。

应该使用什么 else 来推断出要创建的数组的元素类型?

第一个元素?如果是这样,那么......是不是很不一致......

auto a = make_array(1, 3.0);
auto b = make_array(3.0, 1);

......这两个人的数组类型不同?

当然,可以SFINAE或static_assert所有类型的std::make_array传递的参数都相同,但是你人为地限制使用该函数很多 。考虑:

short x = 3;
auto c = make_array(x, 42); // Should this be a compiler error? I'd say no ...

您可以进一步放宽对“相同”类型的要求(在某种意义上)兼容的类型。但是,你不是已经超过std::common_type ......的一半了吗?

(probably) official reasoning (N3824)的目的是提供“类似元组”的接口以及“类似阵列”的接口。前者的行为类似于std::make_tuplestd::make_pair并且推导出一些合适的(因此常见的)类型,后者反映了原始数组声明,如...

int arr [] = {1,2,3};

... 不推断元素的类型,而只是数组长度。

答案 1 :(得分:1)

这不是您问题的直接答案,而是您想要的可能解决方案。

您可以通过实现自己的函数帮助程序来解决它。有一些技巧可以强制执行严格的缩小转换,而不是使用通用类型来推断元素的类型。可以通过检查每个参数的std::is_same来实现它:

template <typename T, typename... Args>
constexpr auto make_array(Args&&... args) -> std::array<T, sizeof...(Args)>
{
    static_assert((std::is_same<std::remove_cv_t<T>, std::decay_t<Args>>{} && ...), 
                  "arguments shall be of same type.");
    return {{std::forward<Args>(args)...}};
}

int main()
{
    auto a = make_array<int>(1, 2, 3);

    // ↓ error: static_assert failed "arguments shall be of same type."
    //auto b = make_array<int>(1, 2, 3.f);
}

123的类型为int,因此检查通过。如果你试图通过,例如类型float的值,静态断言将不允许它编译,因为is_same<int, float>解析为false。

std::make_array的唯一区别在于,您需要提供元素的类型(例如make_array<int>),因此不会根据您的参数推断出常见类型。只会从参数中推断出大小。

此处也不能缩小转换范围,因为参数的类型必须与您提供的类型完全相同。