简体   繁体   English

将lambda转换为std :: tr1 :: function

[英]Converting a lambda to a std::tr1::function

Using visual studio 2008 with the tr1 service pack and Intel C++ Compiler 11.1.071 [IA-32], this is related to my other question 使用visual studio 2008和tr1服务包以及英特尔C ++编译器11.1.071 [IA-32],这与我的其他问题有关

I'm attempting to write a functional map for c++ which would work somewhat like the ruby version 我正在尝试编写一个c ++的功能映射,它的工作方式有点像ruby版本

strings = [2,4].map { |e| e.to_s }

So i've defined the following function in the VlcFunctional namespace 所以我在VlcFunctional命名空间中定义了以下函数

template<typename Container, typename U>
vector<U> map(const Container& container, std::tr1::function<U(Container::value_type)> f)
{
    vector<U> transformedValues(container.size());
    int index = -1; 
    BOOST_FOREACH(const auto& element, container)
    {
        transformedValues.at(++index) = f(element);
    }
    return transformedValues; 
}

and you can call this like so (Note that the function template arguments are defined explicitly): 你可以像这样调用它(注意函数模板参数是明确定义的):

vector<int> test;
test.push_back(2); test.push_back(4); 
vector<string> mappedData2 = VlcFunctional::map<vector<int>,string>(test, [](int i) -> string
{
    return ToString(i);
});

Or like so (Note that the function template arguments aren't defined explicitly) 或者像这样(注意函数模板参数没有明确定义)

std::tr1::function f = [](int i) -> string { return ToString(i); };
vector<string> mappedData2 = VlcFunctional::map<vector<int>,string>(test, f);

But crucially, NOT LIKE THIS 但至关重要的是,不要这样

vector<string> mappedData2 = VlcFunctional::map(test, [](int i) -> string { return ToString(i); });

Without the explicit definition of hte template arguments, it doesn't know which template to use and falls over with a compile error 如果没有hte模板参数的明确定义,它就不知道要使用哪个模板并因编译错误而失败

 ..\tests\VlcFunctional_test.cpp(106): error: no instance of function template "VlcFunctional::map" matches the argument list, argument types are: (std::vector<int, std::allocator<int>>, __lambda3)

Having to define the template arguments makes it a much more bulky syntax and I'm aiming for minimal cruft at the call site - any ideas on why it doesn't know how do the conversion? 必须定义模板参数使它成为一个更庞大的语法,我的目标是在调用网站上最小化 - 任何想法为什么它不知道如何转换? Is this a compiler issue or does the language not allow for this type of template argument inference? 这是编译器问题还是该语言不允许这种类型的模板参数推断?

The problem is that a lambda is not a std::function even if it can be converted. 问题是lambda不是std::function即使它可以被转换。 When deducing type arguments, the compiler is not allowed to perform conversions on the actual provided arguments. 在推导类型参数时,不允许编译器对实际提供的参数执行转换。 I would look for a way to have the compiler detect the type U and let the second argument free for the compiler to deduce: 我想找一种方法让编译器检测类型U并让第二个参数可供编译器推导出来:

template <typename Container, typename Functor>
std::vector< XXX > VlcFunctional::map( Container &, Functor )...

Now the issue is what to write in XXX. 现在问题是在XXX写什么。 I don't have the same compiler that you do, and all C++0x features are still a little tricky. 我没有你做的相同编译器,所有C ++ 0x功能仍然有点棘手。 I would first try to use decltype : 我会先尝试使用decltype

template <typename Container, typename Functor>
auto VlcFunctional::map( Container & c, Functor f ) -> std::vector< decltype(f(*c.begin())) > ...

Or maybe type traits if the compiler does not support decltype yet. 或者,如果编译器还不支持decltype则可以输入traits。

Also note that the code you are writting is quite unidiomatic in C++. 另请注意,您正在编写的代码在C ++中非常简单。 Usually when manipulating containers the functions are implemented in terms of iterators, and your whole map is basically the old std::transform : 通常在操作容器时,函数是根据迭代器实现的,而整个映射基本上都是旧的std::transform

std::vector<int> v = { 1, 2, 3, 4, 5 };
std::vector<std::string> s;
std::transform( v.begin(), v.end(), std::back_inserter(s), [](int x) { return ToString(x); } );

Where std::transform is the C++ version of your map function. 其中std::transformmap函数的C ++版本。 While the syntax is more cumbersome, the advantage is that you can apply it to any container, and produce the output to any other container, so the transformed container is not fixed to std::vector . 虽然语法更麻烦,但优点是您可以将它应用于任何容器,并将输出生成到任何其他容器,因此转换后的容器不会固定到std::vector

EDIT: A third approach, probably easier to implement with your current compiler support is manually providing just the return type of the lambda as template argument, and letting the compiler deduce the rest: 编辑:第三种方法,可能更容易实现当前的编译器支持是手动提供lambda的返回类型作为模板参数,并让编译器推断其余的:

template <typename LambdaReturn, typename Container, typename Functor>
std::vector<LambdaReturn> map( Container const & c, Functor f )
{
   std::vector<LambdaReturn> ret;
   std::transform( c.begin(), c.end(), std::back_inserter(ret), f );
   return ret;
}
int main() {
   std::vector<int> v{ 1, 2, 3, 4, 5 };
   auto strs = map<std::string>( v, [](int x) {return ToString(x); });
}

Even if you want to add syntactic sugar to your map function, there is no need to manually implement it when you can use existing functionality. 即使您想将语法糖添加到map函数中,也可以在使用现有功能时手动实现它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM