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

时间:2011-02-09 19:28:16

标签: c++ gcc overloading sfinae function-templates

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

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

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

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

我的意图是有一个机制,在编译时根据特殊功能是否可用来选择正确的重载函数模板。我有两个函数运行,它将struct作为参数,因此它们可以调用相应的函数。

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)而无需任何额外参数或&lt;&gt;。如果这不起作用,我的代码有问题吗?

此外,我有兴趣了解这里发生了什么以及为什么这会推断出这样的事情,所以我需要<A>A而不是B?我不知道标准是什么,如果编译器之间有所不同,但至少gcc4.4.4在Linux上和gcc 4.0.1在Mac上工作就像我所描述的那样。

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

2 个答案:

答案 0 :(得分:1)

对于这种特殊情况,你可以这样做,这很简单:

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

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

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

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

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

见约翰内斯的回答。 : - )

答案 1 :(得分:1)

这将是有效的。它排序假设正常和特殊的两个函数是互斥的(即,其中一个具有其中一个的类没有另一个)。我相信你可以根据你的目的调整它。当然,这会使用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。