In my code, I have functional templates containing lambda expressions that depend on some template parameters. Recently, I got linker errors, possibly due to updating my g ++ compiler, but unfortunately I don’t know for sure.
I will give a small example demonstrating the problem. Since this is a linker problem, we need to create a couple of files to demonstrate this. We have common.hpp
that contains the generic template function, two modules a.cpp
/ a.hpp
and b.cpp
/ b.hpp
using this function and the main.cpp
module containing the main
function.
// common.hpp #include <algorithm> template <class Iterator, typename Iterator::value_type x> void my_transform(Iterator begin, Iterator end) { std::transform(begin, end, begin, [] (typename Iterator::value_type y) { return x+y; }); }
a.cpp
file:
a.hpp
file
#include <vector> void a(std::vector<int>& vec);
b.cpp
file:
// b.cpp
b.hpp
file
#include <vector> void b(std::vector<int>& vec);
File main.cpp
int main() { return 0; }
If I compile and link using
g++-4.7 -std=c++11 -c a.cpp g++-4.7 -std=c++11 -c b.cpp g++-4.7 -std=c++11 -c main.cpp g++ ao bo main.o
I get a multiple-definition
error:
b.cpp:(.text+0x30): multiple definition of `void my_transform<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, 17>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)::{lambda(int)#1}::operator int (*)(int)() const' ao:a.cpp:(.text+0x30): first defined here
This basically suggests that the lambda expression is already defined in a. Good. If I change the template parameter in b
from 5 to 7, everything works.
Questions:
- Is this what I should expect or is it a bug in
g++
? I am very sure that I compiled this code with an earlier version of the debian g++-4.7
package g++-4.7
. - Are there any workarounds besides using lambda? I think if the received characters were static, there would be no problems. Update: Workaround: Make my_transform
static
or inline
.
This question is not very important. There is no problem with the “don't use lambda here” approach, but I'm curious. :)