Variadic模板方法和std :: function - 编译错误

时间:2015-06-09 17:46:33

标签: c++ templates c++11 variadic-templates

我确定错误很简单愚蠢,但我看不到错误。这是代码:

myCollection.put("hello", 937234L, 2);

这就是错误:

  

' void CAsyncTask :: exec(const std :: function   &,Args&& ...)' :无法推断出' const的模板参数   std :: function&'用[   ResultType = void]

#include <future> template <typename ResultType> class Foo { public: template <typename ...Args> void exec(const std::function<ResultType(Args...)>& task, Args&&... args) {} }; int main() { Foo<void>().exec([](){}); return 0; } 也不起作用(而且我更不希望手动指定Foo<void>().exec<void>([](){})类型)。

有关建议答案的更新:以下代码确实有效。 Args

但这个问题真的没有解决方法吗?我可以以某种方式扩展我的模板来推断lambda参数吗?

3 个答案:

答案 0 :(得分:3)

您可以尝试将exec的签名更改为

template<typename Fn, typename... Args> 
void exec(Fn&& task, Args&&... args)

然后在函数

中构造你的std :: function

答案 1 :(得分:2)

正如Pradhan所提到的,std::function的确切类型无法从lambda中推断出来。您可以明确地强制转换它来解决问题:

Foo<void>().exec(std::function<void()>([](){}));

或者,您可以简单地为函数使用其他类型名称,而无需创建std::function

template <typename Callable, typename ...Args>
void exec(Callable&& task, Args&&... args);

然后Callable会接受几种类型的仿函数,包括lambdas。

请注意,与模板解决方案相比,使用std::function个对象会有很小的性能损失。

您还可以添加static_assert以确保可以使用给定的参数调用Callable,并显示有意义的消息,而不是让编译器在实际调用时生成一个消息。 / p>

答案 2 :(得分:2)

lambada不是std::function,因此无法从中推断出类型。您需要将std::function部分设为不可导出的上下文:

template<class T>struct identity_t{using type=T;};
template<class T>using identity=typename identity_t<T>::type;

template <typename ResultType>
class Foo
{
public:
    template <typename... Args>
    void exec(const std::function<ResultType(identity<Args>...)>& task,
              Args&&... args)
    {}
};

您还可以使用模板约束使函数完全通用;

#include <type_traits>

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

template<class T,class=void>
struct callable:std::false_type{};
template<class F,class... Ts>
using invoker=decltype(std::declval<F>()(std::declval<Ts>()...));
template<class F,class... Ts>
struct callable<F(Ts...),void_t<invoker<F,Ts...>>>:std::true_type{};

template<class R,class S>
using result_eq=std::is_same<std::result_of_t<S>,R>;

#define REQUIRE(cond) std::enable_if_t<(cond)>* = nullptr

template<class R>
class Foo
{
public:
    template<class F, class... Args, REQUIRE(callable<F(Args...)>{}), REQUIRE((result_eq<R, F(Args...)>{}))>
    void exec(F&& f, Args&&...);
};

int main()
{
    Foo<void>().exec([] (int) {}, 4);
}