推断可调用的第一个参数

时间:2016-10-20 18:02:05

标签: c++ c++11 templates

我希望能够推断出一个可调用的第一个参数。我可以让它免费和成员函数工作,但我正在与lambdas挣扎。我可以使用一些技巧吗?

这是一个例子。在以下match函数中,我想使用T

的知识
template<class T>
void match(void (*)(T*, int))   { /* First */ }

template<class T>
void match(void (T::*)(int))    { /* Second */ }

template<class T>
void match(std::function<void(T,int)>)    { /* Third */ }

struct A
{
   void f(int)  {}
};

void g(A*, int) {}

match(&A::f);           // Ok, matches first
match(&g);              // Ok, matches second
match([](A*, int) {});  // Not Ok
match([&](A*, int) {}); // Not Ok

2 个答案:

答案 0 :(得分:2)

你不能。

template<class T>
void g(T*, int) {}

无法正常工作

void g(void*, int) {}
void g(std::string**, int) {}

无效。

同样的问题与lambdas有关。

作为一般规则,您可以询问&#34;我可以使用Y&#34;来调用X,您无法获得签名。

std::function不是lambda,lambda不是std::function。它们是不相关的类型,除了您可以将lambda转换为具有任何兼容签名的std::function这一事实,就像您可以转换任何可调用对象一样。

如果您足够限制问题空间,可以编写一个traits类来提取传入对象上operator()的签名,并将其视为lambda的参数。

这在C ++ 11中是一个坏主意,它在C ++ 14和C ++ 17中通常会变得更糟。 [](auto a, int b){}是C ++ 14中的lambda(许多C ++ 11编译器都支持它),并且第一个参数没有固定类型。

通常,更好的方法是将签名分开捆绑,而不是可调用。这违反了C ++ 11中的DRY(不要重复自己),但在C ++ 14中,lambda只能采用auto&&个参数。

另一种方法是问问题&#34;这些类型中的哪些类型可以工作&#34;哪些可以完成。通常,您没有与您合作的无限类型系列,而是一个枚举集。

答案 1 :(得分:0)

我只知道一种方式:通过std::function

match(std::function<void(A*, int)>([](A*, int) {}));
match(static_cast<std::function<void(A*, int)>>([&](A*, int) {}));