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).

J.N.
  • 8,203
  • 3
  • 29
  • 39
  • Related question: http://stackoverflow.com/questions/5853186/conversion-of-lambda-expression-to-function-pointer – Robᵩ Oct 22 '12 at 01:36
  • @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. – Cheers and hth. - Alf Oct 22 '12 at 01:38
  • @J.N. could you please post a complete example program, if practical? – Cheers and hth. - Alf Oct 22 '12 at 01:40
  • I'll try, but I may not be able to due to confidentiality of some parts ... Many thanks for helping. – J.N. Oct 22 '12 at 01:41
  • 3
    Example posted by Someone Else in the C++ Lounge: http://liveworkspace.org/code/35374b3c9b0d40e8ccc0819eb44d7f9e – Cheers and hth. - Alf Oct 22 '12 at 01:49
  • 1
    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 FieldComparer;`. – jogojapan Oct 22 '12 at 01:49
  • It's clearly a g++ bug. But proving that from the standardese may be hard. – Cheers and hth. - Alf Oct 22 '12 at 01:51
  • @Cheersandhth.-Alf example compiles for me with gcc 4.7.0 under MinGW. – Yuushi Oct 22 '12 at 01:53
  • Please, report the bug to http://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. – jpalecek Oct 22 '12 at 01:55
  • @jpalecek : I was blaming myself up till 5 minutes ago, not the compiler ;) – J.N. Oct 22 '12 at 01:57
  • 2
    @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. – Yuushi Oct 22 '12 at 01:57
  • @Yuushi : 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 ;) – J.N. Oct 22 '12 at 02:01
  • 6
    @J.N. LucDanton mentioned in the C++ lounge that changing the function to internal linkage fixes the problem, and it [seems to compile](http://liveworkspace.org/code/2878cd54827b8cc8f7d6aeecda41c89c) at least if you do that. Maybe that's an option for you? – Praetorian Oct 22 '12 at 02:06
  • 4
    Bug reported at http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55015 – J.N. Oct 22 '12 at 02:10
  • 3
    @Praetorian It completely solves the problem, and it's acceptable for me. Using an anonymous namespace works as well (unsurprisingly). – J.N. Oct 22 '12 at 02:12
  • 2
    Minimal testcase: http://liveworkspace.org/code/6d685397296f6f7b330fefd208d4b4d0 – nneonneo Oct 22 '12 at 04:52
  • @Praetorian 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. – MartinStettner Oct 22 '12 at 20:40
  • @MartinStettner As I mentioned in the comment, it was LucDanton that figured that out. He should be the one posting an answer. – Praetorian Oct 22 '12 at 20:55
  • 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. – J.N. Oct 24 '12 at 21:52
  • @ildjarn : thanks for the precisions. For my information, is that mandated by the standard ? – J.N. Oct 24 '12 at 23:37
  • 2
    @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. – Luc Danton Oct 25 '12 at 02:14
  • @Luc : Ah, I didn't realize that change was present in C++11. Today I learned, thanks. – ildjarn Oct 26 '12 at 18:10
  • 1
    This bug has [now been fixed](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55015#c13) for GCC 4.7.3. Good job everyone! – nneonneo Dec 06 '12 at 16:26

1 Answers1

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.

nneonneo
  • 171,345
  • 36
  • 312
  • 383