12

Intro

When programming in C and C++ you usually split your function prototypes and actual functions into a .h/.hpp and .c/.cpp file. Sadly it's very tedious to transfer the function prototypes from one file to another, and requires opening both files at the same time (or a good memory), as well as a lot of unnecessary typing, especially when changes to the arguments or member names are made.

Example

foo.hpp:

int someFunction(int someArgument);

class someClass
{
     public:
     someClass();
     ~someClass();

     int anotherFunction(int anotherArgument);
};

foo.cpp:

#include "foo.hpp"

int someFunction(int someArgument)
{
    // Code goes here
}

someClass::someClass()
{
    // Code goes here
}

someClass::~someClass()
{
    // Code goes here   
}

int someClass::anotherFunction(int anotherArgument)
{
    // Code goes here
}

Question

Is there a way to automatically create and update the functions in foo.cpp using the definitions and prototypes in foo.hpp?

2 Answers 2

3

Whew, this one was fun!

:g/.*\n^{/yank A<cr>:bn<cr>pkdd:%s/$/;/<cr>:g/::/d B<cr>A<cr><cr>class <cr>{<cr>};<esc>"BP:%s/[^ ]\+:://<cr>j%jyt(kk$p=ipjA<cr>public:<esc>

You can go ahead and map that to a single keystroke in your .vimrc:

nnoremap <C-b> :g/.*\n^{/yank A<cr>:bn<cr>pkdd:%s/$/;/<cr>:g/::/d B<cr>A<cr><cr>class <cr>{<cr>};<esc>"BP:%s/[^ ]\+:://<cr>j%jyt(kk$p=ipjA<cr>public:<esc>

Note that this assumes that the constructor is the first class method to appear. (I could fix that, but I'd rather keep it simple. Please do mention in a comment if you need that fixed.)

This also assumes that your header file buffer is empty and located directly after your source file buffer.

Step-by-step explanation:

:g/.*\n^{/yank A<cr>            Yank all the function definitions (power of g!)
:bn<cr>                         Move to the header file buffer
pkdd                            Put in the function definitions
:%s/$/;/<cr>                    Add semicolons
:g/::/d B<cr>                   Grab the class methods and put them in register B
A<cr><cr>class <cr>{<cr>};<esc> Self-explanatory, add class skeleton
"BP                             Put the class methods in the class
:%s/[^ ]\+:://<cr>              Remove someClass::
j%jyt(kk$p                      Add the actual class name
=ip                             Fix indentation
jA<cr>public:<esc>              Add the `public:' modifier
5
  • 1
    While this is impressive (I'm rather new to vim, so I'm discovering new things every day!), I'm afraid this isn't at all what I need. Maybe I should look into making my own plugin? It seems like a fun thing to do.
    – Lukas
    Feb 6, 2015 at 3:31
  • 2
    @Lukas In what way doesn't a mapping in your .vimrc solve the problem? Simply hitting Ctrl-B will then automatically fill out the header file for you. (I should probably make it clear the header file before replacing it with an updated version, but I have to sleep so I might do that later.) A plugin does sound interesting; keep me updated if you decide to make one. And thanks for the interesting challenge to sharpen up my Vim skills! ;)
    – Doorknob
    Feb 6, 2015 at 3:52
  • 2
    This seems to work in the opposite direction from the request: it creates a header file from the .cpp file. Feb 6, 2015 at 18:51
  • ... which would also be nice, actually, but I think there are some things that can't be known from the definition: e.g., is the declaration supposed to be inline? Are there default arguments? Should the argument names be elided? Aug 26, 2015 at 17:52
  • @200_success Ah, you're right (I don't know why I didn't reply to your comment earlier). When I have time, I'll try to edit my answer to go the other way.
    – Doorknob
    Aug 26, 2015 at 18:59
3

The :GOTOIMPL command from lh-cpp is able to jump to a function definition from its declaration, or to provide a default empty definition in the case none was found.

Some features I can think of:

  • The command already understands comments, exception specifications, keywords that shall not be copied (but possibly copied within comments)(virtual, static, ...).
  • The current scope of the function is decoded (namespaces::classes::...) and correctly reported (i.e. it won't prefix with ns:: if we are within namespace ns{ or a using namespace ns; context.

However:

  • Templates are not (yet) understood.
  • Function body are to be built manually one after the other -- i.e. I haven't yet took the time to execute :GOTOIMPL on all function declarations that ctags could points me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.