如何使用YouCompleteMe在vim中启用C++模板类的自动完成功能

25

使用vim插件YouCompleteMe进行C++代码自动补全时,遇到了问题。使用嵌套的模板类会导致自动补全无法正常工作。

考虑以下示例以复现此行为:

#include <vector>

template<class T>
class foo {
  public:
  void Init();

  private:
  struct bar {
    int foobar;
  };
  bar one_bar;
  std::vector<foo<T>::bar> some_bars;
};

template<class T>
void foo<T>::Init(){
  one_bar.foobar = 0; // completion as expected
  some_bars.at(0).foobar = 0; // no completion neither for "at" nor for "foobar"
}

"some_bars"的代码补全根本不起作用,而"one_bar"的表现符合预期。

如何让这段代码的补全工作?这个问题是否与设置有关,应该是有效的,还是YCM中存在错误?

我的系统基于debian jessie/sid,vim版本为7.4,从GitHub安装了最新版本的YCM。

编辑: 在YCM的bug跟踪器中报告了类似的问题: https://github.com/Valloric/YouCompleteMe/issues/243 https://github.com/Valloric/YouCompleteMe/issues/530

看起来这是clang中的一个错误,而不是YCM中的错误。有人可以证实吗?

编辑2: 我在YCM问题跟踪器中开了另一个问题。 https://github.com/Valloric/YouCompleteMe/issues/1170

意图是获取关于clang中错误的更多信息,并最终在clang问题跟踪器中进行错误报告。

编辑3: 我按照RedX提出的建议步骤,在clang中输入了我的代码以获得完成。 对于代码中讨论的位置,Clang没有提供任何建议。 这显然是YCM无法在vim中提供建议的原因,与YCM或vim无关。

已在clang问题跟踪器中提交错误报告: http://llvm.org/bugs/show_bug.cgi?id=20973


2
这个问题在SO上得到令人信服的答案的机会接近于零。YCM只是clang的一个hacky前端,为什么不直接尝试clang的问题跟踪器呢? - romainl
1
Valloric似乎已经在您发布的问题中确认这是clang中的一个错误/不支持。 - FDinoff
@romainl:我对clang一无所知,因此不知道从哪里开始。这就是为什么我设置了悬赏:我需要有人解释clang的问题所在,并可能在那里开启一个问题。YCM对许多人来说是一个很棒的工具,这是一个使它变得更好的机会。 - static_rtti
@romainl 这不是我的问题。而且我告诉你,我不知道clang的问题在哪里,也不知道它如何使用,因此我无法在他们的邮件列表上发布。 - static_rtti
5
请将以下内容翻译为中文:尝试将此代码片段输入到clang中,并要求提供完成列表。请参见此帖子,了解如何在命令行/标准输入中执行此操作。然后,您可以创建一个可复制的示例。 - RedX
显示剩余9条评论
2个回答

3

据C++的规则,我认为在这种情况下无法获得完成。

如果不知道类型 T,我们就不知道 std::vector<T> 将会有哪些方法,因为C++中每个模板的实例化可以有不同的方法。


1
在这里展示的代码中,即使不知道类型T,所有的完成情况都是清晰可见的。它不是std::vector<T>,而是std::vector<foo<T>::bar>。 - Phil

0

正如@Chris Jefferson上面提到的,从理论上讲是不可能的。 但是这个评论没有考虑到模板特化。

在这里展示的代码中,即使不知道类型T,所有的完成情况都是清楚的。它不是一个std::vector,而是一个std::vector<foo::bar>

这在我尝试为一个没有推导模板的模板编写专门化时,在一个非常不同的上下文中发生了。我将提供我的例子来澄清这种情况。所以假设你有一个枚举器,你有一个meta_info类,它通过模板定义了一个枚举器的大小:

enum class e{a,b};
template <class Enum>
struct meta_info;
template<>
meta_info<e>{
    static constexpr size_t s=2;
}

好的,这个可行并且很不错,但是如果你尝试在一个嵌套在模板类中的枚举器中做同样的事情会发生什么?

template <class Tag>
struct str{
   enum class e{a,b};
}
template <class Enum>
struct meta_info;
template<T>
meta_info<str<T>::e>{
    static constexpr size_t s=2;
}

这段代码无法编译,因为其他部分的代码可能会将 e 更改为另一种特化类型。即使在编译的最初阶段,编译器也没有正式的方法来知道特化是否更改了类型。考虑到自动完成工具大多数情况下只使用包含路径来查找建议,这是不可能的。因此,我希望在 ycm 中能够看到类似于非正式实例化的东西 就像 VS 所做的那样


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接