c++ 为什么概念约束不被认为是上下文类型信息?

agyaoht7  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(106)

请考虑:

void f(int);        // (1)
void f(int, int);   // (2)

auto pf1 = static_cast< void (*)(int) >(f);      // Ok, address of (1)
auto pf2 = static_cast< void (*)(int, int) >(f); // Ok, address of (2)

static_assert(std::invocable<decltype(pf1), int>);      // passed
static_assert(std::invocable<decltype(pf2), int, int>); // passed
static_assert(!std::invocable<decltype(pf2), int>);     // passed

字符串
现在,代替显式强制转换,我想使用概念来帮助编译器进行重载解析:

std::invocable<int> auto pf1 = f;  // Only (1) satisfies, there is no ambiguity


但编译不了。我的问题是为什么?
如果这个例子是可行的,我们可以这样写:

std::string s;
std::ranges::transform(s, s.begin(), std::toupper);

yzuktlbb

yzuktlbb1#

当前,变量声明上的类型约束的唯一作用是隐式地static_assert类型,就像没有类型约束一样推导出的类型满足约束。它没有以任何方式影响重载解析或类型推导。
这对像toupper这样的标准库函数都没有帮助,因为它们中的大多数都没有被指定为 addressable,这意味着你不知道什么重载结构是用来实现它们的,所以不能保证你能够接受一个指针/例如,std::toupper可能被实现为单个函数模板,而不是多个重载。然后只需检查约束不足以使你想要的工作。你需要以某种方式进行模板参数推导,选择一组模板参数,这些模板参数恰好使函数具有int。一般来说,这是一个不可判定的问题。
toupper传递给函数的唯一可靠方法是将其 Package 在lambda中。显式强制转换或::toupper也不能保证有效。此外,无论如何都需要lambda,因为正如问题注解中所提到的,直接调用toupper将导致某些输入的未定义行为。
所以,我怀疑你是否能够提出合理的规则,可以添加到语言中,以实现你想要的行为。
我认为可以添加一些东西,说明如果std::invocable<int> auto pf1 = f;中的重载(模板参数推导后)不满足类型约束。但是如果f被实现为模板而不是多个重载,那么这将没有帮助,而且它也不适用于相同形式的函数参数,因为函数模板上的类型约束是不与单个函数参数相关联,而是与整个函数模板相关联。

相关问题