简体   繁体   中英

Choose Best Available Function Through Tag Inheritance

Assume the user defines some subset of the following functions:

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

Your task is to write a function call_best(int) which calls the first function from the above list that is declared (you may then assume that it is also defined). How do you do that?

First, we define a priority class.

template<unsigned P> struct priority : priority<P-1> {};
template<> struct priority<0> {};

It can be used to give a total order on the functions as follows:

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>{}); }

The Int template parameter and the decltype() make sure that only the defined functions compete for being called (keyword SFINAE). The priority tag class allows us to pick the best one among them.

Note that the SFINAE part only works if you have at least one parameter on which you can template. If anyone has an idea on how to avoid this, please tell me.

Your code will work if you follow the convention of giving your functions a deduced return type (ie auto / decltype(auto) ). This can only be done in C++14 wherein a function with a deduced return type cannot be used until it is defined (even in an unevaluated operand), causing a substitution failure otherwise. Here's your example that works in clang 3.5 but unfortunately not in 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM