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
I’m attempting to write a functional map for c++ which would work somewhat like the ruby version
strings = [2,4].map { |e| e.to_s }
So i’ve defined the following function in the VlcFunctional namespace
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
..\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::functioneven if it can be converted. 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 typeUand let the second argument free for the compiler to deduce:Now the issue is what to write in XXX. I don’t have the same compiler that you do, and all C++0x features are still a little tricky. I would first try to use
decltype:Or maybe type traits if the compiler does not support
decltypeyet.Also note that the code you are writting is quite unidiomatic in C++. Usually when manipulating containers the functions are implemented in terms of iterators, and your whole map is basically the old
std::transform:Where
std::transformis the C++ version of yourmapfunction. 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 tostd::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:
Even if you want to add syntactic sugar to your
mapfunction, there is no need to manually implement it when you can use existing functionality.