C++ std::make_数组公共类型的基本原理

C++ std::make_数组公共类型的基本原理,c++,c++17,C++,C++17,使用公共类型。但是,我的主要问题是,它允许编译本来无法编译的代码: 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

使用公共类型。但是,我的主要问题是,它允许编译本来无法编译的代码:

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
}
模板
无效foo(T a,T b)
{
}
int main()
{
auto arr=std::实验::生成数组(1,3.0);//编译
foo(1,3.0);//a和b类型必须匹配
数组arr2{1,3.0};//缩小转换
}
这不一定是坏事。但我发现这是不一致的。请注意,由于模板参数推断的工作方式,
std::make_array
实际上禁用了推断(因为您明确指定了一个类型),因此这并不能解决问题

在这里使用公共类型的基本原理是什么

std::make_array
使用公共类型

它还应该使用什么来推断要创建的数组的元素类型

第一个要素?如果是这样的话,那么让

auto a = make_array(1, 3.0);
auto b = make_array(3.0, 1);
。。。这两种类型的数组是否不同

当然,可以确定或
static\u断言
传递给
std::make\u array
的所有类型的参数都是相同的,但随后人为地限制了该函数的使用。考虑:

short x = 3;
auto c = make_array(x, 42); // Should this be a compiler error? I'd say no ...
您可以更进一步,将类型“相同”的要求放宽到(在某种意义上)兼容的类型。但是,你不是已经在
std::common_type
上做了一半了吗

其目的是提供“类似元组”的接口以及“类似数组”的接口。前者的作用类似于
std::make_tuple
std::make_pair
并推断出一些合适的(因此是常见的)类型,后者反映了原始数组声明,如

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


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

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

您可以通过实现自己的函数助手来解决这个问题。有一些技巧可以强制执行严格的窄化转换,而不使用公共类型来推断元素的类型。可以通过检查每个参数的
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);
}
模板
constexpr自动生成数组(Args&&…Args)->std::array
{
静态断言((std::is_same{}&…),
“参数应为同一类型。”);
返回{{std::forward(args)…};
}
int main()
{
自动a=生成数组(1,2,3);
// ↓ 错误:静态_assert failed“参数应为相同类型。”
//自动b=生成数组(1,2,3.f);
}
1
2
3
属于
int
类型,因此检查通过。如果您尝试传递例如
float
类型的值,静态断言将不允许编译,因为
是相同的
解析为false

这里与
std::make_array
的唯一区别在于,您需要提供元素的类型(例如
make_array
),因此它不会根据您的参数推断出通用类型。仅从参数中推断出大小

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

好吧,OP建议不要推断类型,宁可编译失败,也不要过分狂热地推断。这不是一个不合理的偏好。