2

Currently, I try to incorporate lemon library in our project. Most developers are on Windows, they compile with MSVC, but I am in charge (for this part) to compile with gcc and clang.

I came across an error with clang that gcc does not reproduce and I managed to reduce the code:

#include <lemon/dfs.h>

int main() {
    lemon::ListDigraph g{};
    lemon::ListDigraph::Node node = g.nodeFromId(42);
    lemon::Dfs<lemon::ListDigraph> dfs{g};
    lemon::SimplePath<lemon::ListDigraph> path = dfs.path(node);
    return 0;
}  

With gcc, no errors.

/usr/bin/g++-5 -std=c++11 -Wall -O3  -I${SRC_ROOT}/external/lemon/latest -I${BIN_ROOT}/lemon -o ${TMP_ROOT}/core/src/core.cpp.o -c ${SRC_ROOT}/core/src/core.cpp

But with clang:

/usr/bin/clang++-3.7 -std=c++11 -Wall -stdlib=libc++ -O3 -I${SRC_ROOT}/external/lemon/latest -I${BIN_ROOT}/lemon -o ${TMP_ROOT}/core/src/core.cpp.o -c ${SRC_ROOT}/core/src/core.cpp

In file included from ${SRC_ROOT}/core/src/core.cpp:1:
In file included from ${SRC_ROOT}/external/lemon/latest/lemon/dfs.h:31:
${SRC_ROOT}/external/lemon/latest/lemon/path.h:408:23: error: no viable
      conversion from 'typename PredMapPath<ListDigraph, NodeMap<Arc> >::RevArcIt' to
      'lemon::ListDigraphBase::Arc'
        data[index] = it;;
                      ^~

Notes:

  • SRC_ROOT, BIN_ROOT, TMP_ROOT are replaced for readability
  • the snippet source code won't work, but should compile (I will correct the real big code)
  • I really need the c++11 features for the real source code.
  • gcc 5
  • clang 3.7
  • lemon 1.3.1

Questions :

  • Did I forget to clang a flag?
  • Does lemon is fully compatible with clang?
  • How to solve this error?
Isammoc
  • 883
  • 5
  • 20
  • which lemon release/development version did you use? – decltype_auto Nov 10 '15 at 17:10
  • Edited (lemon 1.3.1) – Isammoc Nov 10 '15 at 17:18
  • Thanks; that error can be effortlessly reproduced with clang++-3.5 (which widens the audience a little). It's about the old problem of trying to assign ReverseIterators To ForwardIterators; the forward it block just above in `lemon/path.h` compiles without warning. – decltype_auto Nov 10 '15 at 18:14
  • No, it's not; at least the unspecialized RevIt has a cast `operator Arc ()`. – decltype_auto Nov 10 '15 at 18:45
  • What is weird, i tried to compile without `-std=c++11` neither `-stdlib=libc++` and it works without warnings (with modifying original code not to use initializer lists). – Isammoc Nov 10 '15 at 20:03

1 Answers1

2

It's a double dispatch related problem

The code in http://lemon.cs.elte.hu/hg/lemon/file/9fd86ec2cb81/lemon/path.h#l443

template <typename CPath>
void buildRev(const CPath& path) {
    int len = path.length();
    data.resize(len);
    int index = len;
    for (typename CPath::RevArcIt it(path); it != INVALID; ++it) {
        --index;
        data[index] = it;; // sic!
    }
}

relies on this user-defined cast-operator of the iterator on the right hand side

http://lemon.cs.elte.hu/hg/lemon/file/9fd86ec2cb81/lemon/bits/path_dump.h#l139

operator const typename Digraph::Arc() const {
    return path->predMatrixMap(path->source, current);
}

but the left hand type of the assigment expression

http://lemon.cs.elte.hu/hg/lemon/file/9fd86ec2cb81/lemon/list_graph.h#l89

class Arc {
    friend class ListDigraphBase;
    friend class ListDigraph;
protected:
    int id;
    explicit Arc(int pid) { id = pid;}
public:
    Arc() {}
    Arc (Invalid) { id = -1; }
    bool operator==(const Arc& arc) const {return id == arc.id;}
    bool operator!=(const Arc& arc) const {return id != arc.id;}
    bool operator<(const Arc& arc) const {return id < arc.id;}
};

doesn't have a custom assignment operator, but a single-argument custom ctor that clang tries to match against conversions of the right side. And fails.

Patching the right side of above shown lemon/path.h, line #443 with an simple explicit cast operator invocation

   data[index] =  it.operator const typename Digraph::Arc();; 

makes the code at least compile with clang (3.5).

The lemon-developers must decide whether this is desired behavior; a bug report should be filed for this.

decltype_auto
  • 1,706
  • 10
  • 19
  • Wow, thanks for taking that time. Links were useful to understand the mechanisms in place. But I don't understand why gcc and msvc are ok with that but not clang. Does a workaround exist without modifying the library? (I am not a maintainer of lemon) – Isammoc Nov 11 '15 at 09:59
  • 1
    Yw. I'm not connected to lemon either; I use boost::graph almost exclusively. (*In fact I leaned about lemon's mere existence from your post*). About the whys and what-abouts - I suggest you formulate another question with a minimal core language (no "lemon" or any external libs) example that reproduces that difference between those compiler's behavior and tag that with [c++11], [g++], [clang++], [conversion-operator], and [language-lawyer]. I haven't found any duplicate (amazingly enough), although I would not rule out that one exists; but this may be important for the g++ or clang++ teams. – decltype_auto Nov 11 '15 at 13:21
  • that long comment was directed @Isammoc. – decltype_auto Nov 11 '15 at 13:22
  • @Isammoc I tracked that issue down a little and posted a related question here http://stackoverflow.com/questions/33673158/assignment-fails-to-use-a-cast-op-to-const-unrelated-type-with-clang-but-sucee – decltype_auto Nov 12 '15 at 14:04