我遇到了以下问题。我正在使用Xcode 7并且对我的项目没有任何问题。尝试在Visual Studio Express 2015上编译它后,我在代码中收到消息"Error C2668 ambiguous call to overloaded function"
。我找不到任何与视觉工作室有关的问题。
我做了一个应该在VS上使用的最小工作示例(Xcode上没有错误)。奇怪的部分涉及func2
部分。就好像VS编译器无法自动推导出更多类型和/或参数而不是限制。
更新:
Sam Varshavchik提出了一种解决方法,包括使用部分专业化和中间模板类。这是我想避免的解决方案。首先是因为它在上下文中不方便它将在我的代码中应用,第二,因为这个编译错误对我来说不清楚。此错误未显示在Xcode7中,即使在VS中,func2也没有错误。尽管我同意WhiZTiM的解释,但实际情况是,在这种情况下,重载有时会起作用,有时也不行。我真的很想知道原因。
更新2:
根据bogdan的说法,这可能是GCC和MSVC中的一个错误。我打算报告一下。 (第一周,我非常喜欢视觉工作室)
更新3:
在https://connect.microsoft.com/VisualStudio/feedback/details/3076577
报告错误template <class T>
class BX {
public :
BX() {}
~BX() {}
};
template <class T1, class T2>
class G {
public :
G() {}
~G() {}
};
template <template <class T> class T1, class T>
class DT {};
class B {
public :
//I want func to work
template <template <class T> class T1, class T, class M>
static void func(const M& m, const DT<T1, T>* dt, T1<T>& val) {}
template <template <class T> class T1, class T, class M>
static void func(const G<T1<T>, M>& g, const DT<T1, T>* dt, T1<T>& val) {}
//here is a small variation of func as a test
template <template <class T> class T1, class T, class M>
static void func2(const M& m, const DT<T1, T>* dt) {}
template <template <class T> class T1, class T, class M>
static void func2(const G<T1<T>, M>& g, const DT<T1, T>* dt) {}
};
的main.cpp
int main() {
BX< int > bx;
G<BX< int >, int> g;
DT<BX, int>* dt;
B::func(g, dt, bx);//Error C2668 'B::func': ambiguous call to overloaded function
B::func2(g, dt);//no error
}
答案 0 :(得分:3)
你打了这个电话:
B::func(g, dt, bx);
其中:
g
的类型为G<BX< int >, int>
dt
的类型为DT<BX, int>*
bx
的类型为BX< int >
现在你有这两个功能:
template <template <class T> class T1, class T, class M>
static void func(const M& m, const DT<T1, T>* dt, T1<T>& val) {}
//^^^^^^^^^^
template <template <class T> class T1, class T, class M>
static void func(const G<T1<T>, M>& g, const DT<T1, T>* dt, T1<T>& val) {}
//^^^^^^^^^^^^^^^^^^
在重载过程中;并且只考虑函数声明中的第一个参数(因为那些应该使函数声明不同):
M
被推导为G<BX< int >, int>
。 T
可以从bx
推断为int
T1<T>
模板模板类型,从bx
推断为BX< int >
M
会匹配任何内容。G<BX< int >, int>
,与第一个函数相同GCC也会引发歧义错误。
要在传递G<...>
类型时优先考虑第二个重载函数,您需要使用部分特化。 (因为它们的排名高于主要模板)。请参阅
Sam Varshavchik's answer有一种可行的方法。
答案 1 :(得分:2)
所示代码的明显意图是部分功能专业化。
哪个...不起作用。
那么,做什么,做什么......那么,如何将部分函数专业化转换为普通的模板类专业化呢?
我的解决方案专门针对第一个函数参数类型的模板,以消除静态类的歧义,并将其转发给两个终极类方法之一。
一个好的C ++编译器应该能够优化掉额外的函数调用层:
template <class T>
class BX {
public :
BX() {}
~BX() {}
};
template <class Tdata, class Tmetric>
class G {
public :
G() {}
~G() {}
};
template <template <class T> class T1, class T>
class DT {};
template<class M> class B_func;
class B {
public :
template <template <class T> class T1, class T, class M>
static void func(const M& m, const DT<T1, T>* dt, T1<T>& val)
{
B_func<M>::func(m, dt, val);
}
template <template <class T> class T1, class T, class M>
static void func_a(const M& m, const DT<T1, T>* dt, T1<T>& val) {}
template <template <class T> class T1, class T, class M>
static void func_b(const G<T1<T>, M>& g, const DT<T1, T>* dt, T1<T>& val) {}
//here is a small variation of func as a test
template <template <class T> class T1, class T, class M>
static void func2(const M& m, const DT<T1, T>* dt) {}
template <template <class T> class T1, class T, class M>
static void func2(const G<T1<T>, M>& g, const DT<T1, T>* dt) {}
};
template <class M>
class B_func {
public:
template<class two, class three>
static void func(const M& m, const two* dt, three& val)
{
B::func_a(m, dt, val);
}
};
template <template <class T> class T1, class T, class M>
class B_func<G<T1<T>, M>> {
public:
template<class two, class three>
static void func(const G<T1<T>, M>& m, const two* dt, three& val)
{
B::func_b(m, dt, val);
}
};
int main() {
BX< int > bx;
G<BX< int >, int> g;
DT<BX, int>* dt;
B::func(g, dt, bx);
B::func2(g, dt);
return 0;
}
答案 2 :(得分:1)
这看起来像MSVC和GCC中的错误。调用应该解决到第二次重载(Clang和EDG正在这样做)。
对于调用B::func(g, dt, bx)
,名称查找会找到两个func
模板。对它们中的每一个执行模板参数推导和替换,以便生成随后可以参与重载解析的函数模板特化声明。两个模板的扣除成功,我们留下了两个专业:
void B::func<BX, int, G<BX<int>, int>>(const G<BX<int>, int>&, const DT<BX, int>*, BX<int>&);
void B::func<BX, int, int> (const G<BX<int>, int>&, const DT<BX, int>*, BX<int>&);
这两个函数具有相同的参数声明子句,因此显然重载解析无法根据调用参数的转换来区分它们;它必须采用这个过程中的最后两个步骤。
首先,如果其中一个函数是模板特化而另一个函数不是,则优选非模板函数;这里不适用。
最后,它查看了合成两个特化声明的模板;如果根据函数模板的部分排序,其中一个模板比另一个模板更专业,则优选相应的特化。 (这是原始模板重新发挥作用的唯一过程。)
下面的描述不是很准确,并且跳过了一些细节,但我试图专注于与这种情况相关的部分。非常粗略:
首先,从两个模板的函数参数声明中去除引用和cv限定符,产生:
F1(M , const DT<T1, T>*, T1<T>)
F2(G<T2<U>, V>, const DT<T2, U>*, T2<U>)
(更改模板参数名称以避免混淆)
然后,尝试使用另一个模板的函数参数的形式作为参数来调用一个模板,然后反过来。在这种情况下,最后两对相应的参数具有相同的形式,因此推导成功。对于第一对相应的参数:
M
形式的参数中推导出G<T2<U>, V>
; M
被推断为G<T2<U>, V>
。T2
形式的参数中导出U
V
,G<T2<U>, V>
和M
中的M
并不起作用(G<T2<U>, V>
可以是任何东西)。换句话说,M
是一个更具体的&#34;形式比M
;它不能代表F2
可以代表的所有类型;这是更专业的在这种情况下试图形式化的直观含义。
因此,演绎适用于从F1
到F2
的所有相应参数对,但不是相反。这使得F1
在部分排序方面比var fd = new FormData();
fd.append('name', name);
fd.append('description', description);
fd.append('image', image);
$http.post(baseUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
});
更专业。
这意味着在重载分辨率中首选对应于第二个模板的特化。