这类似于这个问题,但更具体。这次,没有编译器按预期工作。
template<class T>
struct nondeduced
{
using type = T;
};
template<class T>
using nondeduced_t = typename nondeduced<T>::type;
template<class... T, class U>
void f(void(*)(nondeduced_t<T>..., U)) {}
void g(int, char) { }
int main()
{
f<int>(g); // error?
}
在上面的例子中,参数包
T
无法被推导出来,但编译器应该能够在对参数包T
进行显式参数替换后推导出U
(在本例中为单个int
)。上述代码也可以不使用
nondeduced_t
技巧而正常工作:template<class... T, class U>
void f(void(*)(T..., U)) {}
因为参数包
T
已经处于无法推导的上下文中,根据[temp.deduct.type]p5。
无法推导的上下文包括:
- 不出现在参数声明列表的末尾的函数参数包。
不幸的是,我测试过的所有编译器(g++/clang)都无法接受这段代码。值得注意的是,以下类似代码在g++和clang上都可以工作。
template<class... T>
void f(void(*)(nondeduced_t<T>..., char)) {}
再次强调,以下两种情况都不适用:
template<class... T>
void f(void(*)(T..., char)) {}
我的期望错了吗?
T...
来推断函数类型?这显然是可行的:template<class...Ts> struct outer { template<class U> void f( void(*)(Ts..., U ) ) {} };
。@JohannesSchaub-litb,有什么不清楚的吗?非推导上下文集合已被列举出来,这是否是其中之一?标准描述了如何推断U
(参见上面的outer
),假设第一个参数没有被推断。 - Yakk - Adam NevraumontT...
应该是贪婪的,它应该不留任何内容给U
去消费,这样就不会有歧义了。对吗? - Yakk - Adam Nevraumont