当相同的约束必须推导出不同类型时,为什么将概念放入类型说明符失败类型推导?

san*_*orn 4 c++ templates c++-concepts type-deduction

我们有:

template <typename ...T> concept bool Numerics = ( std::is_arithmetic_v<T> && ... ) ;
template <typename T>    concept bool Numeric  =   std::is_arithmetic_v<T>;
Run Code Online (Sandbox Code Playgroud)

然后我们让编译器推导出所有数字:

template <typename T, typename U, typename V, typename W> requires Numerics<T,U,V,W>
auto foo(T arg1, U arg2, V arg3, W arg4) {
    return 0.0 + arg1 + arg2 + arg3 + arg4;
}

std::cout << foo (1,2.0,3.0f,4.0l) << "\n";
Run Code Online (Sandbox Code Playgroud)

编译器推导出预期的所有参数类型:

auto foo<int, double, float, long double>(int, double, float, long double):
Run Code Online (Sandbox Code Playgroud)

当我们尝试将约束分配到类型说明符中以编写更短的版本时:

auto foo2(Numeric arg1, Numeric arg2, Numeric arg3, Numeric arg4) {
    return 0.0 + arg1 + arg2 + arg3 + arg4;
}
Run Code Online (Sandbox Code Playgroud)

虽然,编译器令人惊讶地无法推断出这一点:

// err: deduction fails
//
// std::cout << foo2(1,2,3,4.0) << "\n"; 
Run Code Online (Sandbox Code Playgroud)

似乎编译器尝试将所有类型推断为相同类型,这必须在此处失败.

为什么?编译器是否应该能够从相同的约束中推断出不同的类型?

生活

Tri*_*dle 7

这是概念TS中更具争议性的方面之一.当你说

template <typename T> concept bool C = true;

template <C T, C U>
void func(T t, U u);
Run Code Online (Sandbox Code Playgroud)

这被翻译成好像你说的那样

template <typename T, typename U> requires (C<T> && C<U>)
void func(T t, U u);
Run Code Online (Sandbox Code Playgroud)

但是,当您使用"缩写语法"来表示时

void func(C t, C u); 
Run Code Online (Sandbox Code Playgroud)

这被翻译成好像你说的那样

template <typename T> requires C<T>
void func(T t, T u);
Run Code Online (Sandbox Code Playgroud)

许多人认为这是违反直觉的,并且有人建议改变它.然而,其他人(包括了Bjarne Stroustrup的自己)都赞成"一贯演绎"的-见Stroustrup的纸在这里.

在撰写本文时,包含在C++ 20草案中的概念TS的子集不包括缩写语法.目前尚不清楚它是否会在20年结束,如果是这样,它将使用什么样的推论 - 争论仍有待解决.