我有一个问题,即创建一个指向重载函数的函数指针会导致g ++ 4.7和g ++ 4.8上的编译错误,但不会导致g ++ 4.4,g ++ 4.6或clang ++ 3.2(可能还有VS2010)。
通过谷歌搜索以确定问题是使用g ++还是使用我的代码,我仍然无法决定。 适用于函数指针转换的重载决策规则是否与应用于函数调用的规则不同?
这是一个稍微最小化的代码,用于演示此问题:
template < class T >
struct Dummy {
typedef T value_type;
value_type value;
};
template < class T >
typename T::value_type f (const T& x) {
return x.value;
}
template < class T >
T f (Dummy< T > const& x) {
return x.value + 1;
}
int main (int, char**) {
Dummy< int > d = { 1 };
// No ambiguity here
d.value = f(d);
// This is ambiguous for *some* compilers
int (* const f_ptr)(Dummy< int > const&) = f;
return f_ptr( d );
}
clang ++ 3.2,g ++ 4.4和g ++ 4.6使用-Wall -pedantic --std=c++98
编译时没有警告。
g ++ 4.7和g ++ 4.8会出现以下错误消息:
test.cc: In function ‘int main(int, char**)’:
test.cc:15:45: error: converting overloaded function ‘f’ to type ‘int (* const)(const struct Dummy<int>&)’ is ambiguous
test.cc:6:18: error: candidates are: typename T::Type f(const T&) [with T = Dummy<int>; typename T::Type = int]
test.cc:9:3: error: T f(const Dummy<T>&) [with T = int]
这是新版g ++的问题还是我的代码实际上是错误的?
如果是的话,怎么会解决这种模棱两可的问题?
答案 0 :(得分:3)
这是新版g ++的问题还是我的代码实际上是错误的?
我想这是合法代码(但我不太确定)。要添加到列表中:它使用clang 3.3和icc 13.1.3进行编译。
如何解决这种歧义?
您可以使用
int (* const f_ptr)(Dummy< int > const&) = f<int>;
选择第二个重载或
int (* const f_ptr)(Dummy< int > const&) = f<Dummy<int> >;
选择第一个。
如果您不想手动消除歧义(如我上面的建议),我可以建议使用SFINAE消除歧义的解决方法。我假设您可以使用C ++ 11(函数模板的默认模板参数),但我相信一些额外的工作可以扩展到C ++ 98。
将f
的定义更改为:
template < class T, class R = typename T::value_type>
R f (const T&) {
return x.value;
}
template < class T, class R = T>
R f (Dummy< T > const&) {
return x.value + 1;
}
这样,原始行(下面)在gcc(4.7.3和4.8.1)中编译得很好:
int (* const f_ptr)(Dummy< int > const&) = f;