基本上,我希望能够做的是使用任意数量的任何类型的参数lambda并将其转换为std :: function.我尝试过以下方法,两种方法都不起作用.
std::function([](){});//Complains that std::function is missing template parameters
template <typename T> void foo(function<T> f){}
foo([](){});//Complains that it cannot find a matching candidate
Run Code Online (Sandbox Code Playgroud)
但是,下面的代码确实有效,但它不是我想要的,因为它需要明确说明对通用代码不起作用的模板参数.
std::function<void()>([](){});
Run Code Online (Sandbox Code Playgroud)
我整个晚上一直在使用功能和模板,我只是想不出来,所以任何帮助都会非常感激.
正如评论中所提到的,我试图这样做的原因是因为我试图使用可变参数模板在C++中实现currying.不幸的是,这在使用lambdas时非常糟糕.例如,我可以使用函数指针传递标准函数.
template <typename R, typename...A>
void foo(R (*f)(A...)) {}
void bar() {}
int main() {
foo(bar);
}
Run Code Online (Sandbox Code Playgroud)
但是,我无法弄清楚如何将lambda传递给这样的可变函数.为什么我对将泛型lambda转换为std :: function感兴趣是因为我可以执行以下操作,但最终要求我明确地将模板参数声明为std :: function,这正是我想要避免的.
template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
foo(std::function<void()>([](){}));
}
Run Code Online (Sandbox Code Playgroud) 我试着编译这段代码:
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>
int main() {
std::vector<int> v{
1,5,4,2,8,5,3,7,9
};
std::cout << *boost::min_element(v | boost::adaptors::transformed(
[](int i) { return -i; })) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译失败,出现以下错误消息(在长模板实例化小说之后):
/usr/local/include/boost/iterator/transform_iterator.hpp:84:26: error: use of deleted function ‘main()::<lambda(int)>::<lambda>()’
../main.cpp:12:5: error: a lambda closure type has a deleted default constructor
Run Code Online (Sandbox Code Playgroud)
我搜索了问题,并在Boost Users邮件列表存档中找到了这个问题.它建议使用#define BOOST_RESULT_OF_USE_DECLTYPE可以解决问题.我把它放在我的代码的最开头,但它仍然没有编译.错误消息的长度似乎要短得多,但最后的错误消息是相同的.我目前正在使用Boost 1.50.
这可能是什么问题?有没有办法让这项工作?
我正在尝试编写一个包装器make_function,它std::make_pair可以std::function用合适的可调用对象创建一个对象.
就像make_pair对于函数指针一样foo,auto f0 = make_function(foo);创建一个正确类型签名的std::function函数对象f0.只是为了澄清,我不介意偶尔给出类型参数make_function,以防很难(或不可能)从参数中完全推断出类型.
到目前为止我提出的(下面的代码)适用于lambdas,一些函数指针和函子(我没有考虑挥发性).但我无法让它起作用std::bind或std::bind<R>结果.在下面的代码中
auto f2 = make_function(std::bind(foo,_1,_2,_3)); //not OK
Run Code Online (Sandbox Code Playgroud)
不会编译/工作,使用gcc 4.8.1.我猜测,我没有捕捉到operator()了bind正确的结果,但我不知道如何解决它.
任何有关如何解决此案例或改善其他角落案件的帮助表示赞赏.
当然,我的问题是如何修复下面示例中的错误.
对于后台,我可以在这个问题中找到我使用此包装器的一种情况:如何使C++ 11函数采用函数<>参数自动接受lambdas.如果您不批准使用std::function或以我的具体使用方式,请在该帖子中留下您的意见,并在此处讨论技术问题.
---编辑---
从一些评论中,我了解到这是因为模糊性问题(std::bind结果函数调用operator()的模糊性).正如@Mooing Duck的回答所指出的,解决方案是明确地给出参数类型.我已经更新了代码以结合@Mooing Duck的答案中的三个函数(稍微更改了类型参数),这样make_function包装器现在可以像以前一样处理/类型推导明确的情况,并允许指定完整类型签名歧义.
(我的明确案例的原始代码位于:https://stackoverflow.com/a/21665705/683218,可在以下网址进行测试:https://ideone.com/UhAk91):
#include <functional>
#include <utility>
#include <iostream>
#include <functional>
using namespace std;
// For …Run Code Online (Sandbox Code Playgroud) 编辑: 问题中概述的方法由于一些原因而存在问题。最后,我以另一种方式解决了这个问题,请参见下面的答案。
我有一些模板类,其中template参数应该是与某个签名匹配的可调用对象。如果用户提供了一个不可调用的模板参数或与预期的签名不匹配的模板参数,则编译将在回调机制内部深处失败,并且所产生的错误消息将很难破译。相反,static_assert如果给定的template参数无效,我想能够用来预先提供一个很好的,易于理解的错误消息。不幸的是,这似乎很难做到。
我正在使用以下设置:
#include <type_traits>
namespace detail {
template <typename Function, typename Sig>
struct check_function
{
static constexpr bool value =
std::is_convertible<Function, typename std::decay<Sig>::type>::value;
};
template <typename, typename>
struct check_functor;
template <typename Functor, typename Ret, typename... Args>
struct check_functor<Functor, Ret(Args...)>
{
typedef Ret (Functor::*Memfn) (Args...);
static constexpr bool value =
check_function<decltype(&Functor::operator()), Memfn>::value;
};
} // end namespace detail
template <typename Func, typename Sig>
struct check_function_signature
{
using Type =
typename std::conditional<
std::is_function<Func>::value,
detail::check_function<Func, Sig>,
detail::check_functor<Func, Sig>>::type;
static …Run Code Online (Sandbox Code Playgroud) c++ ×4
c++11 ×4
lambda ×3
boost ×1
boost-range ×1
c++14 ×1
function ×1
std-function ×1
templates ×1
type-traits ×1