通过标记继承选择最佳可用功能

时间:2014-10-03 09:29:05

标签: c++ c++11

假设用户定义了以下功能的某些子集:

void f(int) {}
void g(int) {}
void h(int) {}
// ...

你的任务是编写一个函数call_best(int),它调用上面列出的第一个函数(你可以假设它也被定义)。你是怎么做到的?

2 个答案:

答案 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()
}

clang 3.5  g++ 4.9