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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

886閲覧

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

DaiGuard

総合スコア159

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/11/15 02:44

編集2017/11/15 11:47

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

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

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

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

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

/* 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を使用しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

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/15 15:27

編集2017/11/15 15:36
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DaiGuard

2017/11/17 14:49

ご返答が遅れて申し訳ありません。 そして、情報ありがとうございます。 自分の開発環境g++5.4.0にはexperimental/souce_locationがなかっため 7.2.0にアップデートして試してみたところ、source_locationを使用することで やりたいことができることが確認できました。 ありがとうございました。
guest

0

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

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

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

投稿2017/11/15 02:56

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DaiGuard

2017/11/15 11:51

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

0

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

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

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

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

投稿2017/11/15 04:47

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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

投稿2017/11/17 14:55

DaiGuard

総合スコア159

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

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

C++

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

投稿2017/11/15 02:53

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DaiGuard

2017/11/15 11:48

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問