Lambda not found when defined in an inline function in G++ 4.7
Asked Answered
B

1

32

I have the following function defined in a header file (the library it is part of aims at being header-only):

typedef bool (*FieldComparer)(const std::string&, const std::string&);

inline FieldComparer
GetComparer(const std::string& query, string& separator)
{
    if (query.find('=') != std::string::npos) {
        separator = "=";
        return [](const string& s1, const string& s2) { return s1 == s2; };
    }
    else if (query.find('^') != string::npos) {
        separator = "^";
        return [](const string& s1, const string& s2) { return boost::starts_with(s1, s2); };
    }
    else if (query.find('*') != string::npos) {
        separator = "*";
        return [](const string& s1, const string& s2) { return boost::contains(s1, s2); };
    }
    else if (query.find('!') != string::npos) {
        separator = "!";
        return [](const string& s1, const string& s2) { return s1 != s2; };
    }
    else
        throw std::invalid_argument("Search: could not find operator in query string.");
}


template <class Description>
inline void
Search(Table<Description>& table, const std::string& query,
        std::function<void(const std::string&)> callback, int begin, int limit)
{
    string separator;
    auto comparer = GetComparer(query, separator);

    ... do stuff with comparer ...
}

I am trying to compile a small simple program that includes this file but I get undefined references to all the lambdas at link time. When I say simple there's a single CPP that compiles but can't link. Here the first error:

obj/sample.o: In function `DataModel::GetComparer(std::string const&, std::string&)::{lambda(std::string const&, std::string const&)#1}::operator bool (*)(std::string const&, std::string const&)() const':
/home/julien/workspace_dma/src/DataModel/Search.h:23: undefined reference to `DataModel::GetComparer(std::string const&, std::string&)::{lambda(std::string const&, std::string const&)#1}::_FUN(std::string const&, std::string const&)'

It's happening since I have upgraded to GCC 4.7.2, it used to work fine in GCC 4.6.2 (Ubuntu versions in case that helps). While I know workarounds to solve the problem, I am wondering what I am doing wrong or not understand properly. Since the lambas are inside the inline function they should be defined in any translation unit that uses that function.

-- EDIT --

One more thing worth noting: the Search and GetComparer function are not used in the sample program.

Search is used in a member function of Table<Description> (I can't post the full class):

template <class Description>
void Table<Description>::Search(const std::string& query,
        std::function<void(const std::string&)> callback, int begin, int count)
{
    DataModel::Search(*this, query, callback, begin, count);
}

But neither are called from the sample.cpp file. That file test other features of Table which are unrelated. If I comment the call in the member, the code compiles and links. (I need the member function, it's virtual, it's part of a type erasure class above Table).

Baresark answered 22/10, 2012 at 1:28 Comment(23)
Related question: #5853686Carlenacarlene
@Robᵩ: while it's related I don't think it's relevant. That other question is about a shortcoming of Visual C++ 10.0 plus about a lambda with capture. This question is about a g++ compiler bug.Dead
@Baresark could you please post a complete example program, if practical?Dead
I'll try, but I may not be able to due to confidentiality of some parts ... Many thanks for helping.Baresark
Example posted by Someone Else in the C++ Lounge: liveworkspace.org/code/35374b3c9b0d40e8ccc0819eb44d7f9eDead
I get the same error with a simple main program that calls GetComparer. The error disappears if I use a function object, rather than a function pointer: tyepdef std::function<bool(const std::string&, const std::string&)> FieldComparer;.Niko
It's clearly a g++ bug. But proving that from the standardese may be hard.Dead
@Cheersandhth.-Alf example compiles for me with gcc 4.7.0 under MinGW.Narwhal
Please, report the bug to gcc.gnu.org/bugzilla so that it has some chance of getting fixed. Posting questions here may help in getting peoples' attention, but there is no answer that will fix your compiler.Indolence
@Indolence : I was blaming myself up till 5 minutes ago, not the compiler ;)Baresark
@J.N Have you tried removing the inline? That seems to fix the problem on the liveworkspace link. Still, looks like you've found a compiler bug.Narwhal
@Narwhal : no because unlike the liveworkspace stuff my code is in a header file, the inline is required. That library was meant to be header only ... I'll see if it's worth changing or not ;)Baresark
@Baresark LucDanton mentioned in the C++ lounge that changing the function to internal linkage fixes the problem, and it seems to compile at least if you do that. Maybe that's an option for you?Hypertensive
Bug reported at gcc.gnu.org/bugzilla/show_bug.cgi?id=55015Baresark
@Hypertensive It completely solves the problem, and it's acceptable for me. Using an anonymous namespace works as well (unsurprisingly).Baresark
Minimal testcase: liveworkspace.org/code/6d685397296f6f7b330fefd208d4b4d0Viaticum
@Hypertensive I suggest you post an answer (perhaps also mentioning that this is a compiler bug). You could get your well-deserved rep points and the question would no longer appear as unanswered.Staub
@Staub As I mentioned in the comment, it was LucDanton that figured that out. He should be the one posting an answer.Hypertensive
As far as I know they do: anonymous namespaces are equivalent to static because both make the object they describe visible only in the current translation unit only.Baresark
@ildjarn : thanks for the precisions. For my information, is that mandated by the standard ?Baresark
@ildjarn That unnamed namespaces imply internal linkage is a C++11 standardization of a previous, widely adopted non-conforming (but impossible to observe just from C++) practice. See 3.5 Program and linkage [basic.link] paragraph 4.Dumah
@Luc : Ah, I didn't realize that change was present in C++11. Today I learned, thanks.Unitary
This bug has now been fixed for GCC 4.7.3. Good job everyone!Viaticum
V
5

A bug report has been filed with the GCC team, and one of the developers has confirmed the issue on trunk.

In the mean time, as LucDanton pointed out in chat, declaring the function static will solve the problem.

Viaticum answered 22/10, 2012 at 1:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.