[ C++で開発 ]

C++ファイル拡張子とEmacs

編集モードと拡張子

Emacsには、C++-modeがあります。Emacsは、以下の表に示すようにファイル拡張子によって編集モードを判断しています。

ファイル名(拡張子)と編集モード
拡張子 モード 拡張子 モード
.h c-mode .c c-mode
.hh c++-mode .cc c++-mode
.hpp .cpp
.H .C
.hxx .cxx
.h++ .c++

この場合、ヘッダファイルを拡張子'.h'としているとc-modeになってしまいます。c++-modeにする設定をEmacsに行います。

  1. ファイルを開いてから、毎回次のコマンドを実行する。(とっても面倒ですね)
    M-x c++-mode RET
  2. ファイル先頭に次の記述を行う。
    // -*- C++ -*-
  3. 拡張子.hをc++-modeに割り付け直すように、.emacsに記述する。
    ;; C++
    ; ヘッダファイル(.h)をc++モードで開く
    (setq auto-mode-alist
          (append '(("\\.h$" . c++-mode))
                  auto-mode-alist))

ちょっと便利な編集機能

新規にヘッダファイルを作成するときのインクルードガード

ヘッダファイルを新規に作成する場合、auto-insert-modeを有効にしておくと、ファイル名に応じたインクルードガードを生成します。

M-x auto-insert-mode [RET] としてから、C-x C-fで新規ファイル(例:Hello.h)を開くと、

#ifndef HELLO_H
#define HELLO_H



#endif

となります。

雛形設定

autoinsertには、ユーザで定義した雛形を適用する機能もあります。あらかじめ用意しておいたヘッダファイル、ソースファイルの雛形に、新規作成するファイル名などを展開します。

.emacsの記述

まず、拡張子.hおよび.cppを持つファイルを新規作成するときに、それぞれの雛形ファイルを設定します。

  1. 雛形ファイルの場所と拡張子の対応付け
(require 'autoinsert)
;; テンプレート格納用ディレクトリ
(setq auto-insert-directory "~/.emacs.d/insert/")
;; ファイル拡張子とテンプレートの対応
(setq auto-insert-alist
      (append '(
               ("\\.cpp$" . ["template.cpp" my-template])
               ("\\.h$" . ["template.h" my-template])
              ) auto-insert-alist))
(add-hook 'find-file-hooks 'auto-insert)
ここでは、ホームディレクトリの .emacs.d/insert/の中に、拡張子.cpp用の雛形ファイルtemplate.cppと拡張子.h用の雛形ファイルtemplate.hを置いた設定を行っています。
  1. 雛形ファイルに記述するマクロの定義
(require 'cl)
(defvar template-replacements-alists
  '(("%file%" . (lambda () (file-name-nondirectory (buffer-file-name))))
    ("%file-without-ext%" . (lambda () 
          (setq file-without-ext (file-name-sans-extension
                                   (file-name-nondirectory (buffer-file-name))))))
    ("%namespace%" .
         (lambda () (setq namespace (read-from-minibuffer "namespace: "))))
    ("%include%" .
         (lambda () 
           (cond ((string= namespace "") (concat "\"" file-without-ext ".h\""))
                 (t (concat "<" (replace-regexp-in-string "::" "/" namespace) "/"
                            file-without-ext ".h>")))))
    ("%include-guard%" . 
         (lambda ()
           (format "%s_H_"
                   (upcase (concat 
                             (replace-regexp-in-string "::" "_" namespace)
                             (unless (string= namespace "") "_")
                             file-without-ext)))))
    ("%name%" . user-full-name)
    ("%mail%" . (lambda () (identity user-mail-address)))
    ("%cyear%" . (lambda () (substring (current-time-string) -4)))
    ("%bdesc%" . (lambda () (read-from-minibuffer "Brief description: ")))
    ("%namespace-open%" .
       (lambda ()
         (cond ((string= namespace "") "")
               (t (progn 
                   (setq namespace-list (split-string namespace "::"))
                   (setq namespace-text "")
                   (while namespace-list
                     (setq namespace-text (concat namespace-text "namespace "
                                                 (car namespace-list) " {\n"))
                     (setq namespace-list (cdr namespace-list))
                   )
                   (eval namespace-text))))))
    ("%namespace-close%" .
       (lambda ()
         (cond ((string= namespace "") "")
               (t (progn
                   (setq namespace-list (reverse (split-string namespace "::")))
                   (setq namespace-text "")
                   (while namespace-list
                      (setq namespace-text (concat namespace-text "} // " (car namespace-list) "\n"))
                      (setq namespace-list (cdr namespace-list))
                   )
                   (eval namespace-text))))))
))
ここでは、%file% をはじめとしたマクロ定義をしています。これらマクロを雛形ファイルに記述すると、新規ファイル作成時にマクロが実体に展開されます。
  1. 雛形ファイル中のマクロを展開する定義
(defun my-template ()
  (time-stamp)
  (mapc #'(lambda(c)
            (progn
              (goto-char (point-min))
              (replace-string (car c) (funcall (cdr c)) nil)))
        template-replacements-alists)
  (goto-char (point-max))
  (message "done."))

(add-hook 'find-file-not-found-hooks 'auto-insert)

雛形ファイルの用意

template.h
/**
 * %file% - %bdesc%
 *
 * Copyright (c) 2009 TAKAHASHI,Toru <torutk@gmail.com>
 * 
 *
 */
#ifndef %include-guard%
#define %include-guard%

#include <iosfwd>

%namespace-open%

class %file-without-ext% {
public:
    /// Default constructor
    %file-without-ext%();
    /// Destructor
    ~%file-without-ext%();
    /// Copy constructor
    %file-without-ext%(const %file-without-ext%& rhs);
    /// Assignment operator
    %file-without-ext%& operator=(const %file-without-ext%& rhs);
};

/// stream output operator
std::ostream& operator<<(std::ostream& lhs, const %file-without-ext%& rhs);

%namespace-close%
#endif /* %include-guard% */

ファイル先頭コメント、インクルードガード、名前空間、クラスの雛形定義を行っています。

クラスの雛形定義では、デフォルトコンストラクタ、デストラクタ、コピーコンストラクタ、代入演算子、そして外部関数でクラスのストリーム出力を宣言しています。

template.cpp
/**
 * %file% - %bdesc%
 *
 * Copyright (c) 2009 TAKAHASHI,Toru <torutk@gmail.com>
 * 
 *
 */
#include %include%
#include <ostream>

%namespace-open%

/**
 * Default constructor
 */
%file-without-ext%::%file-without-ext%() {
}

/**
 * Default destructor
 */
%file-without-ext%::~%file-without-ext%() {
}

/**
 * Copy constructor
 */
%file-without-ext%::%file-without-ext%(const %file-without-ext%& rhs) {
}

/**
 * Assignment operator
 */
%file-without-ext%& %file-without-ext%::operator=(const %file-without-ext%& rhs) {
    if (this != &rhs) {
        // TODO: implement copy
    }
    return *this;
}

/**
 * stream output operator
 */
std::ostream& operator<<(std::ostream& lhs, const %file-without-ext%& rhs) {
    lhs << "%namespace%::%file-without-ext%{" <<
        // TODO: implement out stream of member data
        "}";
    return lhs;
}
%namespace-close%

雛形で定義したクラス、宣言した外部関数の実装を定義しています。