将visual studio 2008与tr1服务包和英特尔C ++编译器11.1.071 [IA-32]一起使用,这与我的其他question
相关我正在尝试编写一个c ++的功能映射,它的工作方式有点像ruby版本
strings = [2,4].map { |e| e.to_s }
所以我在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;
}
你可以像这样调用它(注意函数模板参数是明确定义的):
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);
});
或者像这样(注意,函数模板参数没有明确定义)
std::tr1::function f = [](int i) -> string { return ToString(i); };
vector<string> mappedData2 = VlcFunctional::map<vector<int>,string>(test, f);
但关键的是,不喜欢这个
vector<string> mappedData2 = VlcFunctional::map(test, [](int i) -> string { return ToString(i); });
如果没有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)
必须定义模板参数使它成为一个更笨重的语法,我的目标是在呼叫站点上最小化 - 任何想法为什么它不知道如何转换?这是编译器问题还是语言不允许这种类型的模板参数推断?
答案 0 :(得分:4)
问题是lambda不是std::function
,即使它可以被转换。在推导类型参数时,不允许编译器对实际提供的参数执行转换。我想找一种方法让编译器检测类型U
并让第二个参数可供编译器推导出来:
template <typename Container, typename Functor>
std::vector< XXX > VlcFunctional::map( Container &, Functor )...
现在问题是在XXX写什么。我没有你做的相同编译器,所有C ++ 0x功能仍然有点棘手。我首先尝试使用decltype
:
template <typename Container, typename Functor>
auto VlcFunctional::map( Container & c, Functor f ) -> std::vector< decltype(f(*c.begin())) > ...
如果编译器还不支持decltype
,也许可以输入特征。
另请注意,您正在编写的代码在C ++中非常简单。通常在操作容器时,函数是根据迭代器实现的,而整个映射基本上都是旧的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); } );
std::transform
是map
函数的C ++版本。虽然语法更麻烦,但优点是您可以将其应用于任何容器,并将输出生成到任何其他容器,因此转换容器不会固定为std::vector
。 / p>
编辑: 使用当前编译器支持可能更容易实现的第三种方法是手动提供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); });
}
即使你想在你的map
函数中添加语法糖,也不需要在使用现有功能时手动实现它。