如何使用SFINAE解决重载函数中的歧义 [英] How to resolve ambiguity in overloaded functions using SFINAE

查看:186
本文介绍了如何使用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
以上是一个切换到这样一个结构的例子:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆