0

I am having problems passing lambda expressions as a parameter to a method of a template class.

If I compile the following code:

main.cpp:

#include "a.h"
int main(int argc, char** argv) {
    A<int> o;
    o.a([&](){  });
}

a.h:

template <typename T>
class A {
public:
    template <typename Lambda>
    void a(const Lambda& f) {
        f();
    }
};

It works fine.

However I do not want to have my implementation of class A in a.h, I want to put the code it in a separate cpp file. So I now have

main.cpp:

Unchanged

a.h:

template <typename T>
class A {
public:
    template <typename Lambda>
    void a(const Lambda& f);
};

a.cpp:

#include "a.h"

template <typename T>
template <typename Lambda>
void A<T>::a(const Lambda& f) {
    f();
}


template class A<int>;

I now get the following error:

In file included from test.cpp:1:0:
a.h:7:7: error: 'void A<T>::a(const Lambda&) [with Lambda = main(int, char**)::__lambda0; T = int]', declared using local type 'const main(int, char**)::__lambda0', is used but never defined [-fpermissive]
  void a(const Lambda& f);
       ^

Why is that? How can I fix it?

I noticed if I put everything in the same cpp file, it works. The problem only occurs when I want to split it this way which is necessary to keep my code organized.

Thank you for your answer

This is very strange because even this works:

main.cpp

#include "a.h"
int main(int argc, char** argv) {
    A<int> o;
    o.a([&](){  });
}
template <typename T>
template <typename Lambda>
void A<T>::a(const Lambda& f) {
    f();
}
template class A<int>;

a.h

template <typename T>
class A {
public:
    template <typename Lambda>
    void a(const Lambda& f);
};

This works. For some reason, It just won't work when I separate the main() and the method implementation in two distinct cpp files.

Why?

jam
  • 803
  • 5
  • 14
  • 2
    Possible duplicate of [Why can templates only be implemented in the header file?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – 463035818_is_not_an_ai Oct 22 '16 at 19:50
  • I think I read that already, it did not fix my issue – jam Oct 22 '16 at 19:52
  • @J.M. did you try the solution in [this answer](http://stackoverflow.com/a/495056/2757079)? – Ahmad Khan Oct 22 '16 at 20:08
  • Yes but I know about this stuff when I don't use lambda it works. I am only getting this issue with a template lambda parameter of a method in a template class – jam Oct 22 '16 at 20:15
  • I believe that other question is not exactly related to my very specific problem – jam Oct 22 '16 at 20:17

3 Answers3

1

OK I think I have found an explanation.

When you split the code of a template class between a .h and a .cpp, You need to make template instantiation explicit.

The problem is that lambda expressions have no specified type, therefore it is not possible to write a template explicit instance of that function for a lambda type.

What I want is impossible: Is it possible to explicitly specialize template to match lambda?

Community
  • 1
  • 1
jam
  • 803
  • 5
  • 14
0

Generally you can't really put the implementation of template functions/classes in a .cpp file. The reason is that when the .cpp file is compiled separately the compiler has no way to know what template parameters will be passed to it. So I think for your situation it's best to leave everything in a header file.

grigor
  • 1,584
  • 1
  • 13
  • 25
  • No but I don't understand, just put all the code in 1 main.cpp file, and you will see it compiles so I am not convinced by your answer – jam Oct 22 '16 at 20:07
  • I mean you can still put then template implementation outside the class in the same .cpp file as the main() – jam Oct 22 '16 at 20:08
  • That's the whole point. Yes if you put the template implementation in the same .cpp file where it's used then it works, because the compiler sees the instantiation of the template in the same file. But if you want to separate the class then it should go into a header file. – grigor Oct 22 '16 at 21:15
0

As others have said it is not possible to separate a template class from its implementation in header and cpp files. However, if the class itself is not a template but one of the member functions accepts a lambda then you can separate the implementation. To do this, do not use template to declare the lambda. Use std::function instead.

Header file a.h.

#include <functional>

namespace xx {
  struct A {
    void square(int num, std::function<void(int)>consumer);
  };
}

CPP file a.cpp.

namespace xx {
  void A::square(int num, std::function<void(int)>consumer) {
    consumer(num * num);
  }
}

Use this as follows.

#include "a.h"
#include <assert.h>

int main() {
  xx::A a;
    
  a.square(10, [](int result) {
      assert(result == 100);
  });
    
  return 0;
}
RajV
  • 6,860
  • 8
  • 44
  • 62