I'm a Scala/Java programmer looking to reintroduce myself to C++ and learn some of the exciting features in C++0x. I wanted to start by designing my own slightly functional collections library, based on Scala's collections, so that I could get a solid understanding of templates. The problem I'm running into is that the compiler doesn't seem to be able to infer any type information for templated function objects.
FC++ seems to have solved this using "Signatures". These seem really similar to the result_type typename, and I thought I would get this using the new function syntax. Can anyone suggest a way to do this sort of thing in C++0x, if it's possible, or at least explain how FC++ was able to accomplish this? Here's a snippet of code I was playing around with
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
template<class T>
class ArrayBuffer {
private:
    vector<T> array;
public:
    ArrayBuffer();
    ArrayBuffer(vector<T> a) : array(a) {}
    template<typename Fn>
    void foreach(Fn fn) {
        for(unsigned int i = 0; i < array.size(); i++) fn(array[i]);
    }
    template<typename Fn>
    auto map(Fn fn) -> ArrayBuffer<decltype(fn(T()))> {
        vector<decltype(fn(T()))> result(array.size());
        for(int unsigned i = 0; i < array.size(); i++) result[i] = fn(array[i]);
        return result;
    }
};
template<typename T>
class Print {
    public:
    void operator()(T elem) { cout<<elem<<endl; }
};
template<typename T>
class Square{
public:
    auto operator()(T elem) -> T {
        return elem * elem;
    }
};
int main() {
    vector<int> some_list = {5, 3, 1, 2, 4};
    ArrayBuffer<int> iterable(some_list);
    ArrayBuffer<int> squared = iterable.map(Square<int>()); // works as expected
    iterable.foreach(Print<int>()); // Prints 25 9 1 4 16 as expected
    iterable.foreach(Print()); // Is there a way or syntax for the compiler to infer that the template must be an int?
    ArrayBuffer<int> squared2 = iterable.map(Square()); // Same as above - compiler should be able to infer the template.
}
                You can make the operator() a template too
class Print {
    public:
    template<typename T>
    void operator()(T elem) { cout<<elem<<endl; }
};
Then you can pass Print(). For passing arguments like in ArrayBuffer<decltype(fn(T()))> I recommend using declval, so you could also work with non-default constructible T
ArrayBuffer<decltype(fn(declval<T>()))>
                        You seem to be reinventing the C++ standard library.  I'm not talking about your containers.
C++ is already pretty functionally equipped.
I think you're missing a few key points about the C++ standard library.
ArrayBuffer::foreach == std::for_eachArrayBuffer::map == std::transform
Here's an example of using C++ functionally. It's also a good example of why C# didn't use iterators. Though they are very powerful, their verbosity is intimidating to C#'s target audience. Java doesn't use iterators as they aren't Object Oriented and the language designers were really anal about that in the beginning.
struct Print
{
   template<typename T>
   void operator()( const T& t )
   { std::cout << t << std::endl; }
};
struct Squared
{
   template<typename T>
   T operator()( const T& t )
   { return t*t; }
};
int main()
{
   std::vector<int> vi;
   std::foreach( vi.begin(), vi.end(), Print());
   std::foreach( vi.begin(), vi.end(), [](int i){ std::cout<<i<<std::endl; } );
   std::vector<int> vi_squared;
   std::transform( vi.begin(), vi.end(), std::back_inserter(vi_squared), Squared() );
   // or
   vi_squared.resize( vi.size() );
   std::transform( vi.begin(), vi.end(), vi_squared.begin(), Squared() );
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With