我正在尝试理解如何在编译时选择正确的重载函数模板,但编译器让我很难过。我可以使它工作,但我不明白发生了什么。让我解释一下。
我有两个结构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上工作就像我所描述的那样。
有人可以对此有所了解吗?谢谢!
答案 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。