Vim + OmniCppComplete:完成作为STL容器的类成员

时间:2010-05-16 08:53:57

标签: c++ linux vim ctags omnicomplete

作为STL容器的类成员的完成失败。

完成对STL容器的本地对象的工作正常。

例如,给定以下文件:

// foo.h
#include <string>

class foo {
public:
    void set_str(const std::string &);

    std::string get_str_reverse( void );

private:
    std::string str;
};

// foo.cpp
#include "foo.h"

using std::string;

string
foo::get_str_reverse ( void )
{
    string temp;

    temp.assign(str);
    reverse(temp.begin(), temp.end());

    return temp;
}       /* -----  end of method foo::get_str  ----- */

void
foo::set_str ( const string &s )
{
    str.assign(s);
}       /* -----  end of method foo::set_str  ----- */

我使用以下方法为这两个文件生成了标签:

ctags -R --c++-kinds=+pl --fields=+iaS --extra=+q .

当我在cpp中输入temp.时,我会按预期获得string成员函数列表。但是如果我输入str. omnicppcomplete吐出“Pattern Not Found”。

我注意到temp.完成仅在我有using std::string;声明时才有效。

如何完成作为STL容器的类成员的工作?

修改

我发现如果对标题进行以下修改,那么STL容器成员的完成就会起作用:

// foo.h
#include <string>

using std::string;

class foo {
public:
    void set_str(const string &);

    string get_str_reverse( void );

private:
    string str;
};

基本上,如果我添加using std::string;然后从std::成员中删除string str;名称空间限定符并重新生成标记文件,则OmniCppComplete能够在{{1}上完成}。

我是否在str.设置let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD"]似乎无关紧要。

问题是将.vimrc声明放在头文件中似乎是一个很大的禁忌,所以我回到原点。

2 个答案:

答案 0 :(得分:1)

我最近搬到了Ubuntu 10.04,其中包括ctags 5.8,我不再像STL这样的STL类有这个问题,但是完成仍然不能像vector那样使用实际的容器。

这是我对ctags 5.7的旧答案:

虽然这有点像黑客攻击,但我找到了一个不会用using指令污染头文件的解决方案,并为OmniCppComplete提供了完成STL容器类成员所需的一切。

#include <string>

#if 0
using std::string;
#else
#   define string std::string
#endif

class foo {
public:
    void set_str(const string &);

    string get_str_reverse( void );

private:
    string str;
};

#ifdef string
#   undef string
#endif

然后修改生成ctags的.vimrc文件中的行,如下所示:

map <C-F12> :!ctags -R --c++-kinds=+pl --fields=+iaS --extra=+q --if0=yes .<CR>

这是如何工作的?当ctags看到--if0=yes选项时,它将采用预处理程序指令的#if 0分支,并在tags文件中生成必要的条目:

str omnitest.h  /^    string str;$/;"   m   class:foo   access:private

OmniCppComplete看到假的using std::string;,当它找不到string的定义时,它会在std命名空间中查找并在那里找到它。

使用g ++进行编译时,输出就是我们想要的。这可以通过预处理器运行文件来验证:

$ g++ omnitest.cpp -E | less

最后你会看到:

# 2 "omnitest.h" 2

class foo {
public:
    void set_str(const std::string &);

    std::string get_str_reverse( void );

private:
    std::string str;
};
# 2 "omnitest.cpp" 2

using std::string;

string foo::get_str_reverse ( void )
{
    string temp;

    temp.assign(str);
    reverse(temp.begin(), temp.end());

    return temp;
}

void foo::set_str ( const string &s )
{
    str.assign(s);
}

例如,如果我在其中一个成员函数中键入this->str.,它现在会给我一个要完成的字符串成员列表。

此技术可用于任何STL容器集,甚至可以自动修改签入时的头或使用Perl脚本从Subversion存储库签出。

这样你的队友就不需要看到你丑陋的黑客了: - )

答案 1 :(得分:0)

尝试设置此变量:

let OmniCpp_NamespaceSearch=1

如果有效,请不要忘记将其放在.vimrc配置文件中!