如何在编译时选择正确的重载函数模板?

发布于 2024-10-16 23:28:29 字数 1379 浏览 7 评论 0原文

我试图了解如何在编译时选择正确的重载函数模板,但编译器给我带来了困难。我可以让它工作,但我不明白发生了什么。让我解释一下。

我有两个结构 A 和 B,如下所示。一个具有特殊功能,另一个具有普通功能。

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

我的意图是拥有一种机制,在编译时根据特殊函数是否可用来选择正确的重载函数模板。我运行了两个函数,它们将结构体作为参数,因此它们可以调用适当的函数。

template<class Func, Func f> struct Sfinae {};

template <typename U>
static void run(U& u, Sfinae<void (U::*)(), &U::special>* = 0)
{
    u.special();
}

template <typename U>
static void run(U& u, ...)
{
    u.normal();
}

我已经用以下方法对此进行了测试,得到了不同的结果:

int main()
{
    A a;
    run<A>(a, 0); // works
    run<A>(a); // ERROR: ambiguous overloaded function
    run(a, 0); // ERROR: A has no member normal
    run(a); // ERROR: ambiguous overloaded function

    B b;
    run<B>(b, 0); // works
    run<B>(b); // works
    run(b, 0); // works
    run(b); // works

    return 0;
}

我想将其用作 run(a) 而不需要任何额外的参数或 <>。当这不起作用时,我的代码是否有问题?

另外,我有兴趣了解这里发生了什么以及为什么会推论出这样的事情,所以我需要为 A 提供 而不是为B?我不知道标准怎么说,也不知道编译器之间是否有所不同,但至少 Linux 上的 gcc4.4.4 和 Mac 上的 gcc 4.0.1 可以像我所描述的那样工作。

有人可以解释一下吗?谢谢!

I'm trying to understand how to select the right overloaded function template at compile-time, but the compiler is giving me a hard time. I can make it work, but I don't understand what is going on. Let me explain.

I have two structs A and B like below. One has a special function and the other a normal.

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

My intension is to have a mechanism, which at compile-time selects the right overloaded function template depending on if the special function is available. I have two functions run, which take the struct as a parameter, so they can call the appropriate function.

template<class Func, Func f> struct Sfinae {};

template <typename U>
static void run(U& u, Sfinae<void (U::*)(), &U::special>* = 0)
{
    u.special();
}

template <typename U>
static void run(U& u, ...)
{
    u.normal();
}

I've tested this with the following, with various results:

int main()
{
    A a;
    run<A>(a, 0); // works
    run<A>(a); // ERROR: ambiguous overloaded function
    run(a, 0); // ERROR: A has no member normal
    run(a); // ERROR: ambiguous overloaded function

    B b;
    run<B>(b, 0); // works
    run<B>(b); // works
    run(b, 0); // works
    run(b); // works

    return 0;
}

I'd like to use it as run(a) without any extra argument or <>. Is there something wrong with my code when this is not working?

Also, I'm interested to understand what is going on here and why this is deducing things like this, so I need to give <A> for A but not for B? I don't know what the standard says and if this is different between compilers, but at least gcc4.4.4 on Linux and gcc 4.0.1 on Mac work like I've described.

Can someone please shed some light on this? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痴梦一场 2024-10-23 23:28:29

这在这里会起作用。它有点假设正常和特殊这两个函数是互斥的(即具有其中一个函数的类不具有另一个函数)。我相信您可以根据您的目的进行调整。当然,这使用了 boost::enable_if

#include <iostream>
#include <boost/utility/enable_if.hpp>

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

template<int> struct Sfinae { enum { value = true }; };

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::special)>,void>::type run(U& u)
{
    u.special();
}

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::normal)>,void>::type run(U& u)
{
    u.normal();
}


int main()
{
    A a;
    run(a); // works

    B b;
    run(b); // works

    return 0;
}

这适用于 Linux 上的 gcc 4.6.0。

This here will work. It sort-of assumes that the two functions normal and special are mutually exclusive (i.e. a class that has one of them doesn't have the other). I'm sure you can adapt it to your purpose. This uses boost::enable_if, of course.

#include <iostream>
#include <boost/utility/enable_if.hpp>

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

template<int> struct Sfinae { enum { value = true }; };

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::special)>,void>::type run(U& u)
{
    u.special();
}

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::normal)>,void>::type run(U& u)
{
    u.normal();
}


int main()
{
    A a;
    run(a); // works

    B b;
    run(b); // works

    return 0;
}

This works on gcc 4.6.0 on Linux.

独夜无伴 2024-10-23 23:28:29

对于这种特殊情况,您可以这样做,这非常简单:

template <typename U>
static void run(U & u)
{
    u.special();
}

template <>
static void run<B>(B &u)
{
    u.normal();
}

或者,您可以简单地删除模板,并编写两个重载函数。我同意,这并不能以更一般的方式解决它。

也许,本主题将帮助您找到通用解决方案:

是否可以编写一个模板来检查函数是否存在?

请参阅 Johannes 的回答。 :-)

For this particular situation you can do this, which is very simple:

template <typename U>
static void run(U & u)
{
    u.special();
}

template <>
static void run<B>(B &u)
{
    u.normal();
}

Or, you can simply remove template, and write two overloaded functions. I agree, this doesn't solve it in more general way.

Maybe, this topic will help you finding a general solution:

Is it possible to write a template to check for a function's existence?

See Johannes's answer. :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文