16

テンプレート パラメーターに対して推定される型をコンパイラに強制的に表示させる簡単な方法はありますか? たとえば、与えられた

template<typename T>
void f(T&& parameter);

const volatile int * const pInt = nullptr;
f(pInt);

Tへの呼び出しで推定される型を確認したい場合がありますf。( だと思いますconst volatile int *&が、確かではありません。) または与えられた

template<typename T>
void f(T parameter);

int numbers[] = { 5, 4, 3, 2, 1 };
f(numbers);

への呼び出しにあるTと推定される私の推測が正しいかどうかを知りたいと思うかもしれません。int*f

サードパーティのライブラリ ソリューション (Boost など) がある場合は、それについて知りたいと思いますが、推定された型を含むコンパイル診断を強制する簡単な方法があるかどうかも知りたいです。

4

4 に答える 4

18

リンク時の解決策:

私のプラットフォーム (OS X) では、興味のある関数の定義を差し引いた完全な短いプログラムを作成するだけで、リンカにこの情報を提供してもらうことができます。

template<typename T>
void f(T&& parameter);  // purposefully not defined

int
main()
{
    const volatile int * const pInt = nullptr;
    f(pInt);
}

Undefined symbols for architecture x86_64:
  "void f<int const volatile* const&>(int const volatile* const&&&)", referenced from:
      _main in test-9ncEvm.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

確かに、「トリプル参照」を取得します。これは、(参照の崩壊による) 左辺値参照として解釈されるべきであり、デマングリング バグです (おそらく修正できるはずです)。


ランタイム ソリューション:

type_name<T>()はこの種のものに便利な関数を用意しています。完全に移植可能なものは可能ですが、私にとっては最適ではありません。ここにあります:

#include <type_traits>
#include <typeinfo>
#include <string>

template <typename T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::string r = 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;
}

次のように使用できます。

#include <iostream>

template<typename T>
void f(T&& parameter)
{
    std::cout << type_name<T>() << '\n';
}

int
main()
{
    const volatile int * const pInt = nullptr;
    f(pInt);
}

私にとっては、次のように出力されます。

PVKi const&

それはひどく友好的な出力ではありません。あなたの経験はより良いかもしれません。私のプラットフォーム ABI はItanium ABIに基づいています。そして、この ABI には次の機能が含まれています。

namespace abi
{
    extern "C"
    char*
    __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
}

これを使用して、C++ シンボルを人間が読める形式にデマングルできます。type_name<T>()これを利用するために更新されたものは次のとおりです。

#include <type_traits>
#include <typeinfo>
#include <string>
#include <memory>
#include <cstdlib>
#include <cxxabi.h>

template <typename T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
        (
            abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr),
            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;
}

そして今、前のmain()印刷物:

int const volatile* const&
于 2013-08-22T00:19:17.323 に答える