質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.94%

#defineでメンバ関数のような名前の関数を定義したい

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,680

score 123

前提・実現したいこと

現在、C/C++でプログラムのログやメッセージを標準出力するクラスを作成しています。
その出力に実行したソースコード名、行数を表示したく、以下のようなソースを書いています

今のやり方だとせっかく出力用の関数をAppMonitorクラスにまとめているのに
msg()としてしか呼び出すことができない。

これをAppMonitor::msg()のようなメンバ関数のように呼び出したい

見た目だけの問題なんですが、
知見をいただけないでしょうか?

※追記
defineで定義することにこだわっていません。
AppMonitor::msg()を呼び出すだけで、呼び出し先の
FILELINEを受け取れる方法が知りたいです。

/* msg()を実行した先のファイル名と行数を追記する定義 */
#define msg(format, ...) AppMonitor::message(format, __FILE__, __LINE__, __VA_ARGS__)
/* 実際に作りたい定義 */
// #define AppMonitor::msg(format, ...) AppMonitor::message(format, __FILE__, __FILE__, __VA_ARGS__)

/* プログラムの標準出力をまとめるクラス */
class AppMonitor{
    /* メッセージを出力するメンバ関数 */
    template<typename... Rest>    // 可変長引数のためのテンプレート
    static void message(const char* format,    // printf用のフォーマット文字列
                        const char* file,      // msg()からもらうファイル名
                        const int line,        // msg()からもらう行数
                        const Rest&... rest){  // 可変長引数
        /* printf用フォーマットとファイル名,行数を合わせる*/
        std::string str = std::string(file) + " " 
                        + std::to_string(line) + " "
                        + std::string(format);

        /* printfで出力 */
        printf(str.c_str(), rest...);
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

開発環境はUbuntu 16.04, コンパイラはgcc 5.4.0
C++11を使用しています

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+4

defineで定義することにこだわっていません。
AppMonitor::msg()を呼び出すだけで、呼び出し先の__FILE____LINE__を受け取れる方法が知りたいです。 

(私が知る限りは)そのような方法は存在しません。__FILE____LINE__はプリプロセッサにより展開されるため、マクロ以外での解法は存在しないと思います。

それ以降は他回答者の方と同じです。マクロ名(プリプロセッサで処理)とそれ以外の名前(コンパイラで処理)は明確に使い分けることを強くお勧めします。


一応、プログラミング言語C++の実験的な拡張「Fundamentals TS v2」の中に所望の機能に近いものは存在します。
http://en.cppreference.com/w/cpp/experimental/source_location

GCCは対応済みClangは未対応のようです。(MSVCやICCは不明ですが多分未対応でしょう)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/17 23:49

    ご返答が遅れて申し訳ありません。
    そして、情報ありがとうございます。

    自分の開発環境g++5.4.0にはexperimental/souce_locationがなかっため
    7.2.0にアップデートして試してみたところ、source_locationを使用することで
    やりたいことができることが確認できました。

    ありがとうございました。

    キャンセル

+2

そもそも論にはなりますが、小文字の名前をつけて、関数と区別の付かないマクロを作ること自体、得策ではないと考えます。

というのも、マクロはソースコードの段階で展開されてしまうので、引数などの扱いが通常の関数と違ってくるからです。

「ソースコードの行数を表示する」というマクロならではの操作を行っている以上、全て大文字のマクロらしい名前にすることをおすすめします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/15 20:51

    ご指摘いただきありがとうございます。

    私自身もdefineで定義するのは気持よくないのですが
    AppMonitor::msg()を呼び出すときに
    使用者側が意識しなくても__FILE__,__LINE__が
    メッセージに追記されるようにしたかったのですが、
    他にやり方が思いつかなかったのです。

    他にいい方法がありましたら教えていただけると
    助かります。

    キャンセル

+1

#defineでメンバ関数のような名前の関数を定義したい

できませんししてはいけません。

#defineマクロは単純なテキスト置換処理なので、C/C++構文規則を無視してとにかく置換してしまいます。どういうことかというと、例えばmsg()のような関数っぽいマクロを定義してしまうと、他の場所で同じ名前の関数を書いたときに、それも問答無用で置換します。当然書いたことと違う内容でコンパイルされるので、トンチンカンなエラーメッセージに悩まされる羽目になります。エラーが出ればまだしも、場合によってはコンパイルが通ってしまって動かすと何かおかしいけどどこが悪いのか判らない、といった最悪の状況に陥る危険性もあります(今時の賢いIDEなら色で見分けが付くかもしれませんが)。

maisumakunさんが書かれているように、マクロはマクロと判る名前にするのが鉄則です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

こんにちは。

以下で AppMonitor::msg(...)と書けますよ。
本当に見た目だけなので見る人を混乱させるため、あまり良い記述ではないとは思いますが。

#define msg(format, ...) message(format, __FILE__, __LINE__, __VA_ARGS__)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/15 20:48

    ご回答いただきありがとうございます。
    こうすれば書けるんですね。気づきませんでした。
    試してみたいと思います。

    キャンセル

0

GCCのバージョンを5.4.0 → 7.2.0にアップデートし、

experimental/source_locationを以下の
ソースコードで使用することでできました。

※インストールしてすぐはsource_locationヘッダーファイル中で
エラーが発生して使用できないため、ヘッダーの修正が必要でした。

// main.cpp

#include <cstdio>
#include <experimental/source_location>


void print_location(const char* __file = __builtin_FILE(),
                    const char* __func = __builtin_FUNCTION(),
                    const int   __line = __builtin_LINE())
{
    printf("%s %s %d\n", __file, __func, __line);
}


void test3(void) 
{
    print_location();
}

void test2(void) 
{
    print_location();

    test3();
}

void test1(void) 
{
    print_location();

    test2();
}

int main(int argc, char** argv)
{
    print_location();

    test1();

    return 0;
}
// ターミナル出力
main.cpp main 34
main.cpp test1 27
main.cpp test2 20
main.cpp test3 15

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.94%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る