假设用户定义了以下功能的某些子集:
void f(int) {}
void g(int) {}
void h(int) {}
// ...
你的任务是编写一个函数call_best(int)
,它调用上面列出的第一个函数(你可以假设它也被定义)。你是怎么做到的?
答案 0 :(得分:4)
首先,我们定义一个优先级。
template<unsigned P> struct priority : priority<P-1> {};
template<> struct priority<0> {};
它可以用来给出函数的总顺序如下:
template<class Int> auto call_best(Int i, priority<2>) -> decltype(f(i)) { return f(i); }
template<class Int> auto call_best(Int i, priority<1>) -> decltype(g(i)) { return g(i); }
template<class Int> auto call_best(Int i, priority<0>) -> decltype(h(i)) { return h(i); }
void call_best(int i) { call_best(i, priority<2>{}); }
Int
模板参数和decltype()
确保仅定义的函数竞争被调用(关键字SFINAE)。 priority
标记类允许我们选择其中最好的一个。
请注意,只有在至少有一个参数可以模板化时,SFINAE部件才有效。如果有人知道如何避免这种情况,请告诉我。
答案 1 :(得分:0)
如果您遵循为您的函数提供推断的返回类型(即auto
/ decltype(auto)
)的约定,则您的代码将有效。这只能在C ++ 14中完成,其中具有推导的返回类型的函数在被定义之前不能被使用(即使在未评估的操作数中),否则导致替换失败。这是你在clang 3.5中运行的例子,但不幸的是没有在g ++ 4.9中。
template<unsigned P> struct priority : priority<P-1> {};
template<> struct priority<0> {};
// ********
auto f(int);
auto g(int);
auto h(int) { std::cout << "h()"; }
// ********
template<class Int> auto call_best(Int i, priority<2>) -> decltype(f(i)) { return f(i); }
template<class Int> auto call_best(Int i, priority<1>) -> decltype(g(i)) { return g(i); }
template<class Int> auto call_best(Int i, priority<0>) -> decltype(h(i)) { return h(i); }
void call_best(int i) { call_best(i, priority<2>{}); }
int main()
{
call_best(0); // calls h()
}