编译时选择函数指针

时间:2015-07-13 20:18:46

标签: c++11 function-pointers

我想编译时选择函数指针。 类似于下面的

中的functionListAutomatic
int funk( int a, int b ) { return a * b / 2; }

template< typename T0, typename T1 >
int null_func( T0 a, T1 b ) { return 0; }

tuple< int( *)(int, int), int( *)(int, float) > functionList {
    funk,
    null_func<int, float>
};

// Pseudo code.
tuple< int( *)(int, int), int( *)(int, float) > functionListAutomatic {
    condition( funk_exist( funk( int, int ) )   , funk, null_func<int, int> ),
    condition( funk_exist( funk( int, string ) ), funk, null_func<int, string> ),
};

void main() {
    int res0 = get<0>( functionList )(1, 2);
    int res1 = get<1>( functionList )(1, 2);
}

我无法弄清楚如何做到这一点。

我知道如何制作funk_exist以便在编译时进行评估(我使用了这个变体:https://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector)。但是funk和null_func这两个参数会导致问题。编译器尝试查找funk(int,string)函数,并在评估funk_exist()之前失败。我需要一个表达式来评估funk_exist()然后评估funk(int,string),如果funk_exist()的计算结果为false。

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

namespace details {
  template<class...>struct voider{using type=void;};
  template<class...Ts>using void_t=typename voider<Ts...>::type;

  template<template<class...>class Z, class, class...Ts>
  struct can_apply:std::false_type{};
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z,void_t<Z<Ts...>>,Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;

样板注入! 1

添加funk:

template<class...Ts>
funk_r = decltype(funk(std::declval<Ts>()...));
template<class...Ts>
can_funk = can_apply<funk_r, Ts...>;

现在我们知道我们是否可以放心。

但谁会放心? funk_miester

template<class lhs, class rhs, class=void>
struct funk_miester {
  decltype(null_func<lhs,rhs>) operator()()const{
    return null_func<lhs, rhs>;
  }
};
template<class lhs, class rhs>
struct funk_miester<lhs, rhs, std::enable_if_t< can_funk<lhs,rhs>{} >> {
  funk_r<lhs,rhs>(*)(lhs, rhs) operator()()const{
    return [](lhs l, rhs r)->funk_r<lhs,rhs> {
      return funk(l,r);
    };
  }
};

并在此行下方查看结果:

tuple< int( *)(int, int), int( *)(int, float) > functionListAutomatic (
  funk_miester<int,int>{}(),
  funk_miester<int,string>{}()
);

你很有趣。

请注意,我检查是否可以在funk中调用can_funk,但是您可以将其替换为您想要的任何特征,只要它生成编译时bool。

在我的情况下,lambda充当适配器,所以如果签名不匹配,它仍然会生成一个函数指针。

1 这只是给我一个特征来检测我是否可以在某些参数上调用funk。你有自己的,所以你不必使用它。