从第一个参数

时间:2018-09-08 03:16:45

标签: c++ templates

我是元编程的新手。第二个参数将与传递的功能参数相同。我想从Func推论出第二种参数类型,在这里需要帮助。

template<typename Func>
void execute(Func func, decltype(Func) t) {
    std::cout << func(t) << std::endl;
}

int main() {
    std::function<int(float)> func1 = [](float f) { return int(f); };
    execute(func1,1.5);
    return 0;
}

这可行,但是我不想声明其他typenameme T,因为该信息已经在Func中提供了,所以为什么不推论。

template<typename Func, typename T>
void execute(Func func, T t) {
    std::cout << func(t) << std::endl;
}

5 个答案:

答案 0 :(得分:3)

在您的示例中,无需知道确切的参数类型,因此,最简单的解决方案是使用可变参数模板。只需获取一个参数包并转发它们:

template<typename Func, typename... Args>
void execute(Func func, Args&&... a) {
    std::cout << func(std::forward<Args>(a)...) << std::endl;
}

int main() {
    auto func1 = [](float f) { return int { f }; };
    execute(func1, 1.5);
    auto func2 = [](int i) { return float { i }; };
    execute(func2, 15);
    auto func3 = [](int a, int b, int c) { return a * b + c; };
    execute(func3, 3, 4, 5);
    return 0;
}

答案 1 :(得分:2)

  

我想从Func推论出第二种参数类型

     

我不想声明其他typename T

除了在binding with the argument之后将可调用对象传递给函数之外,我看不到任何简单的解决方案。

以下内容将确保您的第二个要求,而无需过多更改原始代码。

#include <functional>
#include <iostream>

template<typename Func>
void execute(Func func) {
    std::cout << func() << std::endl;
}
int main() 
{
    auto func1 = std::bind([](float f) { return int(f); }, 2.5f);
    execute(func1);
    return 0;
}

答案 2 :(得分:2)

您应该执行此操作。如果这样做,您的示例将停止工作,因为您的函数是int(float),但是参数是double

#include <functional>
#include <iostream>

template<typename Arg>
void execute(std::function<int(Arg)> func, Arg t) {
    std::cout << func(t) << std::endl;
}

int main() {
    std::function<int(float)> func1 = [](float f) { return int(f); };
    execute(func1,1.5);
    return 0;
}

这不会编译。 Live demo

保持T参数完全正确。

答案 3 :(得分:1)

您正在寻找的是一种类型特征,该特征可以访问函数签名中使用的类型。标准库中没有这样的类型特征。因此,您要么需要使用实现一个的库,要么自己实现。

如果可以使用boost,它们将在其类型特征中完全实现此功能:https://www.boost.org/doc/libs/1_68_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html您想使用argN_type成员来获取第N个参数的类型。

如果不能使用boost,则需要实现自己的类型特征以使参数类型可用。可能看起来像这样:

// Base case for non-function types
template<typename T>
struct func_types { };

// Case for any generic function signature
template<typename Return, typename ...Args>
struct func_types<Return(Args...)>
{
    using ReturnType = Return;
    using ArgsTuple = std::tuple<Args...>;

    template<std::size_t N>
    struct args
    {
        using Type = std::tuple_element_t<N, ArgsTuple>;
    };
};

// Specialization for function pointers
template<typename Return, typename ...Args>
struct func_types<std::function<Return(Args...)>> : public func_types<Return(Args...)> { };

// Specialization for std::function
template<typename Return, typename ...Args>
struct func_types<std::function<Return(Args...)>> : public func_types<Return(Args...)> { };


// All further specializations for member functions,
// lambdas, etc. are left as an exercise to the reader

template<typename Func>
void execute(Func func, typename func_types<Func>::template args<0>::Type t)
{
    std::cout << func(t) << std::endl;
}

This example is basically a stripped down version of this blog post。这使用了C ++ 14中添加的功能,因此您需要针对该版本或更高版本进行编译。

答案 4 :(得分:1)

这里是一个例子:

#include <tuple>
#include <type_traits>

template <typename> struct function_traits;

template <typename Function>
struct function_traits
    : public function_traits<decltype(
          &std::remove_reference<Function>::type::operator())> {};

template <typename ClassType, typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (ClassType::*)(Arguments...) const>
    : function_traits<ReturnType (*)(Arguments...)> {};

/* support the non-const operator ()
 * this will work with user defined functors */
template <typename ClassType, typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (ClassType::*)(Arguments...)>
    : function_traits<ReturnType (*)(Arguments...)> {};

template <typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (*)(Arguments...)> {
  typedef ReturnType result_type;

  using argument_tuple = std::tuple<Arguments...>;
  template <std::size_t Index>
  using argument = typename std::tuple_element<Index, argument_tuple>::type;

  static const std::size_t arity = sizeof...(Arguments);
};

template <typename Function, std::size_t Index>
using nth_argument_type =
    typename function_traits<Function>::template argument<Index>;

#include <iostream>
using namespace std;

template <typename FN>
void execute(FN func, nth_argument_type<FN,0> arg0) {
  std::cout << func(arg0) << std::endl;
};

int main() {
  int i = 7;
  auto fn = [](int a) { return a * a; };
  auto fn2 = [](int a) mutable { return a * a; };
  execute(fn, 5);
  execute(fn, i);
  execute(fn2, 5);
  execute(fn2, i);
};