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