如何使用SFINAE解决重载函数中的歧义 [英] How to resolve ambiguity in overloaded functions using SFINAE
问题描述
我有一个令人难以置信的令人兴奋的库,可以翻译点:它应该与任何点类型工作
I have an incredibly exciting library that can translate points: it should work with any point types
template<class T>
auto translate_point(T &p, int x, int y) -> decltype(p.x, p.y, void())
{
p.x += x;
p.y += y;
}
template<class T>
auto translate_point(T &p, int x, int y) -> decltype(p[0], void())
{
p[0] += x;
p[1] += y;
}
translate_point
其中有 x
和 y
成员的点,并且它还将使用元组/可索引容器$ c> x 和 y
分别由第一个和第二个元素表示。
translate_point
will work with points that have public x
and y
members, and it will also work with tuples/indexable containers where x
and y
are represented by the first and second element, respectively.
问题是,另一个库定义了一个有public x
和 y
的点类,但也允许索引: / p>
The problem is, another library defines a point class with public x
and y
, but also allows indexing:
struct StupidPoint
{
int x, y;
int operator[](int i) const
{
if(i == 0) return x;
else if(i == 1) return y;
else throw "you're terrible";
}
};
我使用这两个库的应用程序如下:
My application, using both libraries, is the following:
int main(int argc, char **argv)
{
StupidPoint stupid { 8, 3 };
translate_point(stupid, 5, 2);
return EXIT_SUCCESS;
}
但是这使得GCC(和clang)不开心:
but this makes GCC (and clang) unhappy:
error: call of overloaded ‘translate_point(StupidPoint&, int, int)’ is ambiguous
现在我可以看到为什么会发生这种情况,但我想知道如何解决这个问题(假设我不能改变StupidPoint的内部),如果有是不容易的解决方法,我如何作为一个库实现者使这更容易处理。
Now I can see why this is happening, but I want to know how to fix this (assuming I can't change the internals of StupidPoint), and, if there is no easy workaround, how I might as a library implementer make this easier to deal with.
推荐答案
如果你想优先对于公共 x
/ y
的情况,您可以这样做:
If you want to give precedence to the case having public x
/y
, you can do this:
template<class T>
auto translate_point_impl(int, T &p, int x, int y) -> decltype(p.x, p.y, void())
{
p.x += x;
p.y += y;
}
template<class T>
auto translate_point_impl(char, T &p, int x, int y) -> decltype(p[0], void())
{
p[0] += x;
p[1] += y;
}
template<class T>
void translate_point(T &p, int x, int y) {
translate_point_impl(0, p, x, y);
}
不言而喻,相反的配置是通过切换第一个参数。
It goes without saying that the opposite configuration is given by switching the types of the first parameter.
如果您有三个或更多选项(说 N $ c $
以上是一个切换到这样一个结构的例子:
If you have three or more options (says N
), you can use a trick based on templates.
Here is the example above once switched to such a structure:
template<std::size_t N>
struct choice: choice<N-1> {};
template<>
struct choice<0> {};
template<class T>
auto translate_point_impl(choice<1>, T &p, int x, int y) -> decltype(p.x, p.y, void()) {
p.x += x; p.y += y;
}
template<class T>
auto translate_point_impl(choice<0>, T &p, int x, int y) -> decltype(p[0], void()) {
p[0] += x;
p[1] += y;
}
template<class T>
void translate_point(T &p, int x, int y) {
// use choice<N> as first argument
translate_point_impl(choice<1>{}, p, x, y);
}
正如你所看到的,现在 N
可以假设任何值。
As you can see, now N
can assume any value.
这篇关于如何使用SFINAE解决重载函数中的歧义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!