如何从函数指针中删除参数列表?

时间:2017-10-02 21:04:26

标签: c++ templates template-meta-programming

给定两个或更多示例函数,是否可以编写模板化代码,这些代码能够推导出作为模板参数提供的函数的参数?

这是一个激励性的例子:

void do_something(int value, double amount) {
    std::cout << (value * amount) << std::endl;
}

void do_something_else(std::string const& first, double & second, int third) {
    for(char c : first) 
        if(third / c == 0) 
            second += 13.7;
}

template<void(*Func)(/*???*/)>
struct wrapper {
    using Args = /*???*/;
    void operator()(Args&& ... args) const {
        Func(std::forward<Args>(args)...);
    }
};

int main() {
    wrapper<do_something> obj; //Should be able to deduce Args to be [int, double]
    obj(5, 17.4); //Would call do_something(5, 17.4);
    wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int]
    double value = 5;
    obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70);
}

/*???*/的两种用法中,我试图弄清楚我可以放在哪里来启用这种代码。

以下似乎不起作用,因为Args在首次使用之前没有被定义(以及我必须假设的还有许多语法错误),即使它确实存在,我也是仍然在寻找一个不需要明确写出类型本身的版本:

template<void(*Func)(Args ...), typename ... Args)
struct wrapper {
    void operator()(Args ...args) const {
        Func(std::forward<Args>(args)...);
    }
};

wrapper<do_something, int, double> obj;

4 个答案:

答案 0 :(得分:6)

使用C ++ 17,我们可以使用自动模板非类型参数,使<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/> <div class="container"> <div class="col-xs-12 col-sm-6 pull-right">Y</div> <div class="col-xs-12 col-sm-6 pull-left">X</div> </div>语法 1)成为可能。

至于推断Wrapper<do_something> w{},您可以使用specialization

进行推断
Args...
template <auto* F>
struct Wrapper {};

template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<F>
{
    auto operator()(Args... args) const
    {
        return F(args...);
    }
};

1)没有C ++ 17,就不可能有Wrapper<do_something> w{}; w(10, 11.11); 很好的语法。

你能做的最好的事情是:

Wrapper<do_something> w{}
template <class F, F* func>
struct Wrapper {};

template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<Ret (Args...), F>
{
    auto operator()(Args... args) const
    {
        return F(args...);
    }
};

答案 1 :(得分:4)

使用C ++ 17,您可以这样做:

template <auto FUNC, typename = decltype(FUNC)>
struct wrapper;

template <auto FUNC, typename RETURN, typename ...ARGS>
struct wrapper<FUNC, RETURN (*)(ARGS...)> {
    RETURN operator()(ARGS ...args) {
        return FUNC(args...);
    }
};

我从W.F。answer

那里学到了这种技巧。

答案 2 :(得分:3)

进一步改进C ++ 17版本:减少模板参数和正确的noexcept注释:

template<auto VFnPtr> struct
wrapper;

template<typename TResult, typename... TArgs, TResult ( * VFnPtr)(TArgs...)> struct
wrapper<VFnPtr>
{
    TResult
    operator ()(TArgs... args) const noexcept(noexcept((*VFnPtr)(::std::forward<TArgs>(args)...)))
    {
        return (*VFnPtr)(::std::forward<TArgs>(args)...);
    }
};

答案 3 :(得分:0)

使用C ++ 11,您可以考虑模板make_wrapper辅助函数。但是,使用此方法,函数指针不是模板参数。相反,函数指针由以下示例中名为f_的非静态数据成员“承载”:

#include <iostream>

void do_something(int value, double amount) {
  std::cout << (value * amount) << std::endl;
}

void do_something_else(std::string const& first, double & second, int third) {
  for(char c : first)
    if(third / c == 0)
      second += 13.7;
}

template<class Ret, class... Args>
using function_pointer = Ret(*)(Args...);

template<class Ret, class... Args>
struct wrapper {
  using F = function_pointer<Ret, Args...>;

  F f_;

  explicit constexpr wrapper(F f) noexcept : f_{f} {}

  template<class... PreciseArgs>// not sure if this is required
  Ret operator()(PreciseArgs&&... precise_args) const {
    return f_(std::forward<PreciseArgs>(precise_args)...);
  }
};

template<class Ret, class... Args>
constexpr auto make_wrapper(
  function_pointer<Ret, Args...> f
) -> wrapper<Ret, Args...> {
  return wrapper<Ret, Args...>(f);
}

int main() {
  constexpr auto obj = make_wrapper(do_something);
  obj(5, 17.4);
  constexpr auto obj2 = make_wrapper(do_something_else);
  double value = 5;
  obj2("Hello there!", value, 70);

  return 0;
}