调用模板函数时出现歧义
Ambiguity while calling template function
我有以下问题:
template< typename T >
class A
{};
class B
{
public:
template< typename... T >
void operator()( A<T>... a )
{
std::cout << "A<T>n";
}
template< typename callable >
void operator()( callable f )
{
std::cout << "callablen";
}
};
int main()
{
B b;
A<int> a;
b( a );
}
调用b( a )
是不明确的——我期望输出A<T>
,即执行operator()
的第一个定义。有人知道怎么修吗?
在标准工作草案N4606(包括已发布的C++11和C++14标准)之前,调用确实不明确,Clang拒绝它是正确的。最新草案N4618中引入的一个更改使部分排序规则选择A<T>...
重载。这是最近发生的变化;我们需要给编译器一些时间来实现它。
MSVC 2015 U3和EDG 4.11选择了A<T>...
过载,因此它们以前是不合格的,并且在这方面神奇地符合最新草案。
发生的情况是,在模板参数推导之后,我们有两个重载,这两个重载都是模板专业化的,并且基于转换(显然,这两种重载都是身份转换)同样好,因此重载解决必须求助于函数模板的偏序。
该过程在标准[temp.dexer.partial]中有描述,我们对第8段感兴趣。在草案N4618之前,它说:
如果
A
是从函数参数包转换而来的,并且P
不是参数包,类型推导失败否则,使用类型P
和A
,然后按照中所述进行推导14.8.2.5.如果P
是函数参数包,则将参数模板的每个剩余参数类型的类型A
与键入函数参数包的声明符id的P
。每个比较推导中后续位置的模板参数由函数参数包扩展的模板参数包。如果对于给定类型(参数中的类型),推导成功模板被认为至少与来自参数模板。
(强调上方和下方的矿)
尝试从第一个过载推导到第二个过载,A
是一个包,而P
不是,因此适用上面段落中的第一句话;扣减失败。尝试以另一种方式推导,第三句和第四句适用,但推导再次失败,因为我们试图从一般形式callable
的自变量推导形式A<T>
的自变量。
因此,演绎是双向失败的;两个模板都不比另一个更专业;这通电话含糊不清。
该段的新措辞如下:
使用生成的类型
P
和A
,推导如下如14.8.2.5所述。如果P
是函数参数包,则类型参数模板的每个剩余参数类型的A
为与函数的声明符id的类型P相比参数包。每次比较都会推导的模板参数由展开的模板参数包中的后续位置功能参数包类似地,如果A
从函数参数包,将其与剩余的每个参数进行比较参数模板的类型如果给定的类型,则参数模板中的类型被认为至少为与参数模板中的类型一样专用。
请注意,第一句话已经不见了,取而代之的是强调的一句,这允许从一个packA
推断为一个非packP
。
现在,由于新规则,从A<T>
到callable
的推导成功了,但反过来仍然失败(没有任何变化)。这使得第一个过载更加专业化。
快速修复:您可以在第一个过载中添加一个前导非封装参数:
template<class T, class... Ts> void operator()(A<T>, A<Ts>...)
这将避免对功能参数列表中第一个位置的包和非包进行比较。对于所有编译器来说,非包A<T>
显然比callable
更专业。
如果你需要一个与没有参数的调用匹配的重载,请单独提供一个(对不起…)
谢谢。
我解决了以下问题:
#include <iostream>
template< typename T >
class A
{};
class B
{
public:
template< typename... T >
void operator()( A<T>... a )
{
std::cout << "A<T>n";
}
template< typename T >
void operator()( A<T> a )
{
std::cout << "A<T>n";
}
template< typename callable >
void operator()( callable f )
{
std::cout << "callablen";
}
};
int main()
{
B b;
A<int> a;
b( a );
b( );
}
这允许在没有参数的情况下调用operator()
。
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 数组初始值设定项的构造函数歧义
- 为什么下面带有非常量转换函数的代码没有歧义?
- std::bind 是否实现了 std::ref 和 std::cref 来消除函数调用的歧义?
- 使用 bool 和 const char 重载的 C++ 函数会在没有警告的情况下产生歧义 (MSVC2012)
- C++SFINAE enable_if_t成员函数,如何消除歧义?
- 当存在覆盖歧义函数时,代码如何运行?
- 如何区分宏函数和函数函数而没有任何歧义?
- 模板与常规函数歧义 - UB?
- C++ 类的构造函数和函数调用运算符 () 重载之间的歧义
- 如何解决传递给boost线程的函数中的歧义
- 如何让编译器知道要调用函数的哪个重载以避免歧义?
- 关于模板化函数上传递的右值引用和传递的参数的歧义
- 如何解决以下代码中的函数重载歧义
- C++ 显式多参数构造函数歧义
- c++ 构造函数重载歧义与initializer_list
- 函数调用歧义(用户定义的转换和 Derived2Base 指针转换)
- 如何消除重载模板函数的歧义
- 解决 CRTP 函数重载歧义问题
- Android NDK - SoundTouch 中的歧义函数 fabs()