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>
实际上禁用推导(因为您明确指定了类型),因此无法解决问题。
这里使用普通类型的理由是什么?
答案 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_tuple
或std::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);
}
值1
,2
和3
的类型为int
,因此检查通过。如果你试图通过,例如类型float
的值,静态断言将不允许它编译,因为is_same<int, float>
解析为false。
与std::make_array
的唯一区别在于,您需要提供元素的类型(例如make_array<int>
),因此不会根据您的参数推断出常见类型。只会从参数中推断出大小。
此处也不能缩小转换范围,因为参数的类型必须与您提供的类型完全相同。