views:

71

answers:

2

Hello to everyone,

I wonder if and how it is possible to define a function object inside a classes member function to use it directly with, for example, the std::transform function.
I know the example is a bit stupid, it's just to show the problem I'm confronted with.

File "example.h"

class Example {
  public:
  //.. constructor and destructor stuff
    std::string toString() const; //Converts 'mVal' to a std::string

  private:
    std::vector<int> mVal; //Only one digit numbers are allowed ([0-9])
}

File "example.cpp"

std::string Example::toString() const
{ 
  //The functor which should be used in std::transform
  struct {
    char operator()(const int number) {
      char c;
      //"Convert" 'number' to a char
      return c;
    };
  } functor;

  //Transform the integers to char
  std::string str(mVal.size(), '0'); //Allocate enough space
  std::transform(mVal.begin(), mVal.end(), str.begin(), functor);
  return str;

};//toString()

Ever since I tried to implement a function object directly inside a member function like in "example.cpp", the code doesn't get compiled. The error message I get is:

error: no matching function for call to ‘transform(__gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Example::toString() const::<anonymous struct>&)’

So I think the problem comes up when using the struct "functor" in std::transform. Can someone tell me what the problem is?

Using:
gcc-4.2 compiler under Ubuntu Linux.

Thanks in advance,
René.

+2  A: 

Sadly, this won't work. Standard disallows local classes to be used as template arguments, so the approach fails (please someone, quote the relevant part of the Standard):

14.3.1/2: "A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter."

If you have access to a C++0x compiler this works though.

Local classes could have been powerful, but their use is somewhat limited to the "type erasure idiom":

struct abstract_foo { ... };

template <typename T>
abstract_foo* make_concrete_foo(...)
{
    struct foo : abstract_foo
    {
        // Depends on T
    };

    return new foo(...);
}
Alexandre C.
ISO/IEC 14882 - 14.3.1/2: "A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a *template-argument* for a template *type-parameter*."
In silico
Unfortunately I can't use a C++0x-compiler yet. But thanks for the answer anyway, good to know it's in the upcoming standard.
@pij82: Look at Luther's answer before giving up though, it is sufficient for your needs.
Alexandre C.
+2  A: 

As Alexandre already pointed out, you can't use an type with function scope (or no name at all) as a template parameter. You can however use a static member function of a local type as a functor parameter:

int main()
{
    struct F {
        static int fn(int x)
        {
            return x+x;
        }
    }; 

    int v[5]={1,2,3,4,5};
    std::transform(v+0,v+5,v+0,F::fn);
}

If you need to a local state in your function and don't want to resort to the type erasure idiom, then you can cheat with casting the local type away:

int main()
{
    struct F {
        int k;
        int call (int n) const 
        {

            return n+k;
        }
        static int fn(void *p, int x)
        {
            return ((F*)p)->call(x); 
        }
    }; 

    int v[5]={1,2,3,4,5};
    F f;
    f.k=123;
    std::transform(v+0,v+5,v+0,std::bind1st(std::ptr_fun(F::fn),(void*)&f));
}
Luther Blissett
15 lines for a lambda expression... But yeah, this solves the problem.
Alexandre C.
The first example does the trick. Thanks for that :) .