2

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

我有两个结构 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>A不是给予B?我不知道标准说什么以及编译器之间是否有所不同,但至少 Linux 上的 gcc4.4.4 和 Mac 上的 gcc 4.0.1 像我所描述的那样工作。

有人可以对此有所了解吗?谢谢!

4

2 回答 2

1

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

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

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

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

也许,这个主题将帮助您找到一个通用的解决方案:

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

请参阅约翰内斯的回答。:-)

于 2011-02-09T19:33:46.103 回答
1

这在这里会起作用。它有点假设两个函数 normal 和 special 是互斥的(即具有其中一个的类没有另一个)。我相信你可以根据你的目的调整它。这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。

于 2011-02-09T20:17:38.390 回答