考虑:
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);
当前对声明的类型约束的唯一影响是隐式地
static_assert
推导出的类型就像没有类型约束一样满足约束。未指定它以任何方式影响重载解析或类型推导。
无论哪种方式,对于像
toupper
这样的标准库函数都没有帮助,因为它们中的大多数都没有被指定为addressable,这意味着您不知道使用什么重载结构来实现它们,因此不能保证您可以在任何情况下获取对它们的指针/引用。例如,std::toupper
可以实现为单个函数模板而不是多个重载。那么仅仅检查约束不足以使你想要的工作起作用。您需要以某种方式进行模板参数推导,选择恰好使函数具有 int
的模板参数集。一般来说,这是一个无法判定的问题。
因此,我怀疑您是否能够提出合理的规则,将其添加到语言中以实际实现您想要的行为。
我认为可以添加一些内容,说明如果重载不满足类型约束,则将
f
的重载删除到 std::invocable<int> auto pf1 = f;
中。但是,如果将 f
实现为模板,这将无济于事,并且它也不适用于相同形式的函数参数,因为函数模板上的类型约束不与单个函数参数相关联,而是与整个函数模板相关联.