C++ 为什么模板参数推断会因重载函数而失败?

C++ 为什么模板参数推断会因重载函数而失败?,c++,language-lawyer,template-argument-deduction,C++,Language Lawyer,Template Argument Deduction,我有一个模板函数,它应该接受函数指针和参数,然后用给定的参数调用函数指针(我们称之为invoke)。但是,当我使用重载函数作为参数调用模板函数时,模板推断失败 我使用了enable_if,这样只有一个重载是有效的,但这没有帮助 #包括 #包括 void foo(int,int){} void foo(std::string,std::string){} 模板 结构和 { 枚举{value=And::value}; }; 模板 结构和 { 枚举{value=Val1&&Val2}; }; 模板该&

我有一个模板函数,它应该接受函数指针和参数,然后用给定的参数调用函数指针(我们称之为
invoke
)。但是,当我使用重载函数作为参数调用模板函数时,模板推断失败

我使用了enable_if,这样只有一个重载是有效的,但这没有帮助

#包括
#包括
void foo(int,int){}
void foo(std::string,std::string){}
模板
结构和
{
枚举{value=And::value};
};
模板
结构和
{
枚举{value=Val1&&Val2};
};

模板该
&foo
不是一个函数指针,而是一个重载集。你必须明确:

Invoke(static_cast<void(*)(std::string, std::string)>(&foo), "a", "b");
Invoke(static_cast&foo),“a”、“b”);
为了简化失败的
启用\u if
,您可以使用一个未指定的函数指针类型和一个可变数组包,并检查
是否可开票

这里的问题是,有多个函数可以工作。
Params…
的推导将在您到达模板的SFINAE部分之前进行。当它试图从
void(*fn)(Params…
推断
Params..
时,它匹配
void foo(int,int)
void foo(std::string,std::string)
。由于它找到多个匹配项,17.8.2.1.6.2规定它被视为非推断上下文


因为它不能推断类型,所以会出现硬停止错误。SFINAE只发生在模板参数推导步骤之后,在本例中它无法到达该步骤。

我对vardic模板不太熟悉,但
typename…Params,typename…Args,
似乎不适用。您希望编译器如何区分这两者?但同样,我对vardic模板不太熟悉,所以我可能只是遗漏了一些东西。如果在推导的上下文中,可以使用两个参数包。例如,请参见为什么不定义
模板结构和:std::bool_常量{}?@L.F.因为我没有C++17。另外,如果我这样做了,我可能根本就不会定义
struct和
,而是直接使用折叠表达式,这就是为什么我在问题中使用了关于重载集的标准引号。你能解释一下为什么它不适用于这里吗?不过,我不知道这一点。哦,现在我看到了,SFINAE发生在重载解析期间,这发生在模板参数推导之后。这就是我要找的。Thanks@Tomeamis不完全是。编译器试图推断
参数…
,但无法,因此它将其保留为未推断。然后它推导出
Args…
,然后继续移动到最后一个参数。一旦它到达那里,你会得到一个硬错误,因为
Params…
没有推导出来,你需要它来尝试应用SFINAE。