有没有办法让模板根据if参数是模板类型和值来做特定的事情?

时间:2015-08-11 19:59:31

标签: c++ templates c++11

如果传递函数指针或函数,我想让辅助函数或模板化结构做不同的事情,但如果我正确理解模板系统,这是不可能的,因为一个是类型而另一个是不

我是否正确?如果可能的话,我希望保持我的API相同,将其传递给函子或函数指针,但如果不需要则不会产生存储指针的成本。 E.g:

template <typename T, void(*fn)(T)>
struct X1
{
  T m_t;

  X(T t) : m_t(t) {}
  void invoke() { fn(m_t); }
};

template <typename T, typename F>
struct X2
{
  T m_t;
  F m_f;

  X(T t, F f) : m_t(t), m_f(f) {}
  void invoke() { m_f(m_t); }
};

因此,在这种情况下,我要么让这些结构共享相同的名称,要么让辅助函数使用函数或函数指针实例化相应的结构,这些函数指针放在相同的参数位置并具有相同的装饰在函数/函子周围。

类似的东西:

void fn(int) {}
auto functor = [](int){};
int h = 3;

auto x1 = make_X(h, fn);
auto x2 = make_X(h, functor);

make_X()是我正在寻找的链接。想法?

1 个答案:

答案 0 :(得分:2)

单一责任原则说,围绕函数指针的优化是无状态的,其余的代码应该单独处理。

因此,创建一个无状态函子,在代码的一部分中调用fn

template<class Sig, Sig* fn>
auto stateless() {
  return [](auto&&...args)->decltype(auto){
    return fn(decltype(args)(args)...);
  };
}

这是C ++ 14。在C ++ 11中,您只需手动编写该lambda的等效项。 1

空基优化帮助器使存储类型的空实例变得便宜且容易:

template<class Tag, class T, class=void>
struct ebo {
  ebo( T tin ):t(std::forward<T>(tin)) {}
  T t;
  T& get( Tag ){ return t; }
  T const& get( Tag ) const { return t; }
  ebo(ebo&&)=default;
  ebo(ebo const&)=default;
  ebo&operator=(ebo&&)=default;
  ebo&operator=(ebo const&)=default;
  ebo()=default;
};
template<class Tag, class T>
struct ebo<Tag, T,
  std::enable_if_t<std::is_empty<T>{} && !std::is_final<T>{}>
>:
  T
{
  ebo( T tin ):T(std::forward<T>(tin)) {}
  T& get( Tag ){ return *this; }
  T const& get( Tag ) const { return *this; }
  ebo(ebo&&)=default;
  ebo(ebo const&)=default;
  ebo&operator=(ebo&&)=default;
  ebo&operator=(ebo const&)=default;
  ebo()=default;
};

使用以上内容实施X

struct F_tag {};
template <typename T, typename F>
struct X:ebo<F_tag, F>
{
  X(T tin, F fin):
    ebo<F_tag,F>(std::forward<F>(fin)),
    m_t(std::forward<T>(tin))
 {}

  T m_t;
  void invoke() { this->get(F_tag{})(m_t); }
};
template<class T, class F>
X<T,F> make_X( T t, F f ) {
  return {std::forward<T>(t),std::forward<F>(f)};
}

在使用时,这看起来像:

void fn(int) {}
auto functor = [](int){};
int h = 3;

auto x1 = make_X(h, stateless<void(int),&fn>());
auto x2 = make_X(h, functor);

零字节用于存储fn(int)functor

我按值计算:添加转发参考作为练习。

1 C ++ 11版stateless

template<class Sig, Sig* fn>
struct stateless_t {
  template<class...Ts>
  auto operator()(Ts&&...ts)const
  -> decltype( fn(std::declval<Ts>()...) )
  { return fn(std::forward<Ts>(ts)...); }
};
template<class Sig, Sig* fn>
stateless_t<Sig, fn> stateless() { return {}; }