【问题标题】:"no viable conversion" with lemon for clang but valid for g++用柠檬表示“没有可行的转换”,但对 g++ 有效
【发布时间】:2015-11-10 14:41:04
【问题描述】:

目前,我尝试将柠檬库合并到我们的项目中。 大多数开发人员都在 Windows 上,他们使用 MSVC 编译,但我负责(这部分)使用 gcc 和 clang 编译。

我遇到了一个 gcc 无法重现的 clang 错误,我设法减少了代码:

#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;
}  

使用 gcc,没有错误。

/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

但是用叮当声:

/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;;
                      ^~

注意事项

  • 为便于阅读,SRC_ROOTBIN_ROOTTMP_ROOT 已替换
  • sn-p 源代码不起作用,但应该可以编译(我会更正真正的大代码)
  • 我真的需要真正的源代码的c++11特性。
  • gcc5
  • clang3.7
  • lemon1.3.1

问题

  • 我是不是忘记挂旗了?
  • lemon 是否与 clang 完全兼容?
  • 如何解决这个错误?

【问题讨论】:

  • 您使用的是哪个柠檬发布/开发版本?
  • 已编辑(柠檬 1.3.1)
  • 谢谢;使用 clang++-3.5 可以毫不费力地重现该错误(这稍微扩大了受众范围)。这是关于尝试将 ReverseIterators 分配给 ForwardIterators 的老问题; lemon/path.h 上面的 forward it 块在没有警告的情况下编译。
  • 不,不是;至少非专业的 RevIt 有一个演员 operator Arc ().
  • 奇怪的是,我尝试在没有-std=c++11-stdlib=libc++ 的情况下进行编译,并且它在没有警告的情况下工作(修改原始代码以不使用初始化列表)。

标签: c++11 g++ clang++ lemon-graph-library


【解决方案1】:

这是一个double dispatch相关的问题

中的代码 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!
    }
}

依赖于右侧迭代器的这个用户定义的cast-operator

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);
}

但是赋值表达式的左侧类型

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;}
};

没有自定义赋值运算符,而是一个单参数自定义 ctor,clang 尝试匹配右侧的转换。并且失败了。

修补上面显示的右侧lemon/path.h, line #443 使用简单的显式转换运算符调用

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

使代码至少可以用 clang (3.5) 编译。

柠檬开发者必须决定这是否是期望的行为;应该为此提交错误报告。

【讨论】:

  • 哇,感谢您抽出宝贵的时间。链接有助于理解现有机制。但我不明白为什么 gcc 和 msvc 可以接受,但不能 clang。在不修改库的情况下是否存在解决方法? (我不是柠檬的维护者)
  • Yw。我也没有和柠檬有关;我几乎只使用 boost::graph。 (事实上,我从你的帖子中倾向于柠檬的存在)。关于原因和结果-我建议您使用最小的核心语言(没有“柠檬”或任何外部库)示例来制定另一个问题,该示例重现了那些编译器的行为和使用 [c++11] 标记的行为之间的差异,[ g++]、[clang++]、[conversion-operator] 和 [language-lawyer]。我没有发现任何重复(令人惊讶的是),尽管我不排除存在一个;但这对于 g++ 或 clang++ 团队可能很重要。
  • 那个长评论是针对@Isammoc。
  • @Isammoc 我稍微追踪了这个问题,并在这里发布了一个相关问题stackoverflow.com/questions/33673158/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多