3

I'm trying to pass a callback to a template function, but GCC gives me

error: no matching function for call to ‘Test::iterate(main(int, char**)::<anonymous struct>&)’

Why doesn't this work? (Also, for reasons beyond my control, I can't use C++11.)

I've also tried naming the struct e.g. myvis and calling test.iterate<myvis>(visitor), but that didn't work either.

#include <deque>
#include <iostream>

class Test {
public:
    std::deque<int> d;

    template <typename C>
    void iterate(C& c) {
        for(std::deque<int>::iterator itr = d.begin(); itr != d.end(); itr++) {
            c(*itr);
        }
    }
};

int main(int argc, char** argv) {
    Test test;
    test.d.push_back(1);
    test.d.push_back(2);
    struct {
        void operator()(int x) {
            std::cout << x << std::endl;
        }
    } visitor;
    test.iterate(visitor);
}
Adam Crume
  • 15,614
  • 8
  • 46
  • 50
  • Try defining vistor globally. I think you have a scope issue – Charlie Aug 20 '12 at 21:05
  • The answer can be found in [Using local classes with STL algorithms](http://stackoverflow.com/questions/742607/using-local-classes-with-stl-algorithms). The short version is that in C++03 you cannot use a local class in a template. If you define the visitor outside of `main`, as Charlie suggests, it will work – David Rodríguez - dribeas Aug 20 '12 at 21:06

3 Answers3

3

The C++03 standard says the following in §14.3.1.2 [temp.arg.type]:

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.

Therefore you need a global named struct instead of a local unnamed one, giving you something like the following:

struct Visitor {
    void operator()(int x) {
        std::cout << x << std::endl;
    }
} visitor;
int main(int argc, char** argv) {
    Test test;
    test.d.push_back(1);
    test.d.push_back(2);
    Visitor visitor;
    test.iterate(visitor);
}

The restrictions on local/unnamed typed have been lifted in c++11, so if those reasons not to use it go away someday your code will be fine as is.

Grizzly
  • 19,595
  • 4
  • 60
  • 78
1

You have two errors.

First of all, you cannot use the local type visitor to instantiate the template member function function iterate (this would work in C++11).

Second, you cannot have an anonymous type here. You need a named struct visitor and you would need to pass an instance of that.

#include <deque>
#include <iostream>

struct visitor {
  void operator()(int x) {
    std::cout << x << std::endl;
  }
};

class Test {
public:
  std::deque<int> d;

  template <typename C>
  void iterate(C& c) {
    for(std::deque<int>::iterator itr = d.begin(); itr != d.end(); itr++) {
      c(*itr);
    }
  }
};

int main() {
  Test test;
  test.d.push_back(1);
  test.d.push_back(2);

  visitor v;
  test.iterate(v);
}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

You could make visitor global and you'll also need to name the struct, say something like Visitor.

#include <deque>
#include <iostream>

struct Visitor {
    void operator()(int x) 
    {
       std::cout << x << std::endl;
    }
};


class Test {
public:
    std::deque<int> d;

    template <typename C>
    void iterate(C& c) {
        for(std::deque<int>::iterator itr = d.begin(); itr != d.end(); itr++) {
            c(*itr);
        }
    }
};

int main(int argc, char** argv) {
    Test test;
    test.d.push_back(1);
    test.d.push_back(2);
    Visitor visitor;
    test.iterate(visitor);
}
Grizzly
  • 19,595
  • 4
  • 60
  • 78
MartyE
  • 636
  • 3
  • 7
  • Wouldn't it make more sense to keep the variable local (unlike the struct which must be global)? Afterall unnecessary global variables are rarely a good idea for code simplicity and correctness. – Grizzly Aug 20 '12 at 21:23
  • @Grizzly You are correct, keeping the variable `visitor` local could (and most of the time would) make more sense. Edit made – MartyE Aug 20 '12 at 21:25
  • I took the libery of actually declaring a local variable, since you seem to have missed that in your edit. – Grizzly Aug 20 '12 at 21:32