[解決済み】標準C++で変数の型を表示することは可能ですか?
質問
例えば
int a = 12;
cout << typeof(a) << endl;
期待される出力
int
解決方法は?
非常に古い質問に対するC++11のアップデート。C++で変数の型を表示する。
一般に受け入れられている(そして良い)回答は
typeid(a).name()
ここで
a
は変数名です。
C++11では
decltype(x)
これは式を型に変換することができます。 そして
decltype()
には、独自の非常に興味深いルールがあります。 例えば
decltype(a)
と
decltype((a))
は一般的に異なる型になります(その理由が明らかになれば、それは正当で理解しやすい理由です)。
私たちの信頼できる
typeid(a).name()
この素晴らしい新世界を探索するために、私たちを助けてください。
いいえ。
しかし、そうなるツールはそれほど複雑なものではありません。 そして、そのツールこそ、私がこの質問に対する答えとして使っているものなのです。 この新しいツールを、以下のものと比較対照します。
typeid(a).name()
. そしてこの新しいツールは、実は
typeid(a).name()
.
根本的な問題。
typeid(a).name()
は、cv-qualifiers、reference、および lvalue/rvalue-ness を捨てます。 例えば
const int ci = 0;
std::cout << typeid(ci).name() << '\n';
私の出力の場合。
i
とMSVCの出力で推測しています。
int
すなわち
const
が消えている。 これはQOI(Quality Of Implementation)の問題ではありません。 規格がこの動作を義務付けているのです。
以下、私が推奨しているのは
template <typename T> std::string type_name();
で、このように使われます。
const int ci = 0;
std::cout << type_name<decltype(ci)>() << '\n';
と私にとっては出力です。
int const
<disclaimer>
MSVCでのテストはしていません。
</disclaimer>
でも、やっている人からのフィードバックは大歓迎です。
C++11の解決策
を使っています。
__cxa_demangle
が推奨する非MSVCプラットフォーム用の
イパパドップ
の回答で、demangleの種類を指定しています。 しかし、MSVCでは、私は
typeid
を使用して名前をデマングルします(未検証)。 そして、このコアは、cv-qualifiers と入力型への参照を検出、復元、報告するいくつかの簡単なテストに包まれています。
#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
}
結果
このソリューションで、私はこんなことができるようになりました。
int& foo_lref();
int&& foo_rref();
int foo_value();
int
main()
{
int i = 0;
const int ci = 0;
std::cout << "decltype(i) is " << type_name<decltype(i)>() << '\n';
std::cout << "decltype((i)) is " << type_name<decltype((i))>() << '\n';
std::cout << "decltype(ci) is " << type_name<decltype(ci)>() << '\n';
std::cout << "decltype((ci)) is " << type_name<decltype((ci))>() << '\n';
std::cout << "decltype(static_cast<int&>(i)) is " << type_name<decltype(static_cast<int&>(i))>() << '\n';
std::cout << "decltype(static_cast<int&&>(i)) is " << type_name<decltype(static_cast<int&&>(i))>() << '\n';
std::cout << "decltype(static_cast<int>(i)) is " << type_name<decltype(static_cast<int>(i))>() << '\n';
std::cout << "decltype(foo_lref()) is " << type_name<decltype(foo_lref())>() << '\n';
std::cout << "decltype(foo_rref()) is " << type_name<decltype(foo_rref())>() << '\n';
std::cout << "decltype(foo_value()) is " << type_name<decltype(foo_value())>() << '\n';
}
と出力されます。
decltype(i) is int
decltype((i)) is int&
decltype(ci) is int const
decltype((ci)) is int const&
decltype(static_cast<int&>(i)) is int&
decltype(static_cast<int&&>(i)) is int&&
decltype(static_cast<int>(i)) is int
decltype(foo_lref()) is int&
decltype(foo_rref()) is int&&
decltype(foo_value()) is int
の違いに注意してください(例)。
decltype(i)
と
decltype((i))
. 前者は
宣言
の
i
. 後者は、quot;type" である。
表現
i
. (式が参照型を持つことはありませんが、慣例として
decltype
はlvalueの式をlvalueの参照で表現しています)。
このように、このツールは単に
decltype
また、自分自身のコードの調査やデバッグを行うこともできます。
これに対して、もし私がこれを
typeid(a).name()
失われたcv-qualifiersや参照を追加することなく、出力は次のようになります。
decltype(i) is int
decltype((i)) is int
decltype(ci) is int
decltype((ci)) is int
decltype(static_cast<int&>(i)) is int
decltype(static_cast<int&&>(i)) is int
decltype(static_cast<int>(i)) is int
decltype(foo_lref()) is int
decltype(foo_rref()) is int
decltype(foo_value()) is int
すなわち、すべての参照と cv-qualifier が取り除かれます。
C++14アップデート
ある問題を解決できたと思ったとき、いつも誰かがどこからともなくやってきて、もっといい方法を教えてくれる :-)
この答え から ジャンボリー は、C++14でコンパイル時に型名を取得する方法を示しています。 いくつかの理由から、これは見事な解決策である。
- コンパイル時です!
- ライブラリ(std::libでも)ではなく、コンパイラ自身が仕事をするようになるのです。 つまり、最新の言語機能(ラムダなど)に対して、より正確な結果が得られるということです。
ジャンボリーの 回答 は、VSのためにすべてをレイアウトしているわけではないので、彼のコードを少し手直ししています。 しかし、この回答は多くのビューを獲得しているので、時間をかけてそちらへ行き、彼の回答にアップボートしてください、それがなければ、このアップデートは決して起こらなかったでしょう。
#include <cstddef>
#include <stdexcept>
#include <cstring>
#include <ostream>
#ifndef _MSC_VER
# if __cplusplus < 201103
# define CONSTEXPR11_TN
# define CONSTEXPR14_TN
# define NOEXCEPT_TN
# elif __cplusplus < 201402
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN
# define NOEXCEPT_TN noexcept
# else
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN constexpr
# define NOEXCEPT_TN noexcept
# endif
#else // _MSC_VER
# if _MSC_VER < 1900
# define CONSTEXPR11_TN
# define CONSTEXPR14_TN
# define NOEXCEPT_TN
# elif _MSC_VER < 2000
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN
# define NOEXCEPT_TN noexcept
# else
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN constexpr
# define NOEXCEPT_TN noexcept
# endif
#endif // _MSC_VER
class static_string
{
const char* const p_;
const std::size_t sz_;
public:
typedef const char* const_iterator;
template <std::size_t N>
CONSTEXPR11_TN static_string(const char(&a)[N]) NOEXCEPT_TN
: p_(a)
, sz_(N-1)
{}
CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN
: p_(p)
, sz_(N)
{}
CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}
CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}
CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}
CONSTEXPR11_TN const_iterator end() const NOEXCEPT_TN {return p_ + sz_;}
CONSTEXPR11_TN char operator[](std::size_t n) const
{
return n < sz_ ? p_[n] : throw std::out_of_range("static_string");
}
};
inline
std::ostream&
operator<<(std::ostream& os, static_string const& s)
{
return os.write(s.data(), s.size());
}
template <class T>
CONSTEXPR14_TN
static_string
type_name()
{
#ifdef __clang__
static_string p = __PRETTY_FUNCTION__;
return static_string(p.data() + 31, p.size() - 31 - 1);
#elif defined(__GNUC__)
static_string p = __PRETTY_FUNCTION__;
# if __cplusplus < 201402
return static_string(p.data() + 36, p.size() - 36 - 1);
# else
return static_string(p.data() + 46, p.size() - 46 - 1);
# endif
#elif defined(_MSC_VER)
static_string p = __FUNCSIG__;
return static_string(p.data() + 38, p.size() - 38 - 7);
#endif
}
このコードでは、自動バックオフを
constexpr
もし、あなたがまだ古代のC++11から抜け出せずにいるならば。 また、C++98/03で洞窟の壁に絵を描いているのならば
noexcept
も犠牲になる。
C++17のアップデート
以下のコメントにて
リベルタ
が新しくなったことを指摘しています。
std::string_view
を置き換えることができます。
static_string
:
template <class T>
constexpr
std::string_view
type_name()
{
using namespace std;
#ifdef __clang__
string_view p = __PRETTY_FUNCTION__;
return string_view(p.data() + 34, p.size() - 34 - 1);
#elif defined(__GNUC__)
string_view p = __PRETTY_FUNCTION__;
# if __cplusplus < 201402
return string_view(p.data() + 36, p.size() - 36 - 1);
# else
return string_view(p.data() + 49, p.find(';', 49) - 49);
# endif
#elif defined(_MSC_VER)
string_view p = __FUNCSIG__;
return string_view(p.data() + 84, p.size() - 84 - 7);
#endif
}
以下のコメントでJive Dadsonが非常に素晴らしい探偵をしてくれたおかげで、VS用の定数を更新しました。
更新しました。
を必ずご確認ください。 このリライトは以下の通りです。 で、私の最新の処方では、読めないマジックナンバーを排除しています。
関連
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】C++の余分な資格エラー
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] Bashで変数が設定されているかどうかを確認する方法は?
-
[解決済み] オブジェクトの種類を決定しますか?
-
[解決済み] C++でextern "C "を使用した場合の効果は?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] 型チェック:typeof、GetType、is?
-
[解決済み] C++11の'typedef'と'using'の違いは何ですか?
-
[解決済み】ローカル変数のメモリはスコープ外からアクセスできる?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Visual Studio 2015で「非標準の構文; '&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】指定範囲内の乱数で配列を埋める(C++)
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】変数やフィールドがvoid宣言されている
-
[解決済み] 変数の型を取得する方法を教えてください。