C++ 如何在编译时选择正确的重载函数模板?
我试图理解如何在编译时选择正确的重载函数模板,但编译器给了我一个困难的时间。我能做到,但我不明白发生了什么。让我解释一下 我有两个结构A和B,如下所示。一个具有特殊功能,另一个具有正常功能C++ 如何在编译时选择正确的重载函数模板?,c++,gcc,overloading,sfinae,function-templates,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 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;
}
我想把它作为runa使用,不需要任何额外的参数或参数。当这不起作用时,我的代码是否有问题
另外,我很想知道这里发生了什么,为什么这是这样的推论,所以我需要为A而不是为B而付出?我不知道标准是怎么说的,也不知道编译器之间是否有差异,但至少Linux上的gcc4.4.4和Mac上的gcc4.0.1的工作方式与我描述的一样
有人能解释一下吗?谢谢 对于这种特殊情况,您可以这样做,这非常简单:
template <typename U>
static void run(U & u)
{
u.special();
}
template <>
static void run<B>(B &u)
{
u.normal();
}
或者,您可以简单地删除模板,然后编写两个重载函数。我同意,这并不能从更一般的角度解决问题
也许,本主题将帮助您找到一个通用解决方案:
见约翰的回答:- 这在这里会有用的。它有点假设这两个函数正常和特殊是互斥的,也就是说,一个类有一个函数却没有另一个函数。我相信你能使它适应你的目的。当然,这使用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。为什么要在正常版本的run中使用可变参数?@Zac:可变参数最不适合重载解析。我们的想法是,只有在没有其他匹配项的情况下,才应该选择这个重载。我明白了,但是对于他所展示的内容,没有必要选择它。@Zac,你能扩展你的评论吗?我所展示的只是我试图简化的东西,以展示所涉及的核心部分,以及编译器正在接受/拒绝的内容。我很想得到一个解释,为什么会是这样。根据你所描述的,纳瓦兹给出的答案就是你所需要的。也就是说,您似乎没有对函数中的可变参数执行任何操作,因此不需要它们。只需将模板专门化为需要专门化的类型,其余的则保持通用。谢谢。我知道这一点,但是,如果有很多A和B,并且我希望代码在情况发生变化时也能工作,那么这可能是不切实际的。假设我添加或删除B或A。也谢谢你的链接。虽然我确实想解决我试图实现的目标,但我也有兴趣理解我所描述的特定事情。为什么会这样?谢谢你,米克尔。这解决了问题,但我也有兴趣了解我所看到的代码。例如,我想。。。是推断时最后匹配的。在这里,如果有一个默认参数,并且没有参数传递给函数,则情况似乎不是这样。我不明白这一点,也不知道这是否是预期的行为标准。有什么想法吗?