![](/img/trans.png)
[英]Can class type be deduced from pointer to member function template parameter
[英]How can I see the type deduced for a template type parameter?
是否有一种简单的方法可以强制编译器向我显示模板参数的推导类型? 例如,给定
template<typename T>
void f(T&& parameter);
const volatile int * const pInt = nullptr;
f(pInt);
我可能想看看在调用f
为T
推导出什么类型。 (我认为这是const volatile int *&
,但我不确定。)或者给出
template<typename T>
void f(T parameter);
int numbers[] = { 5, 4, 3, 2, 1 };
f(numbers);
我可能想知道在调用f
时我的推测T
是否被推断为int*
是正确的。
如果有第三方库解决方案(例如,来自Boost),我有兴趣了解它,但我也想知道是否有一种简单的方法可以强制进行包含推导类型的编译诊断。
链接时解决方案:
在我的平台(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&
我尝试了以下g ++ 4.7.2和clang ++ 3.4(trunk 184647); 他们都给
编译时错误,错误消息包含推断类型 。
我无法访问MSVC 12,请检查发生的情况并提供反馈。
#include <string>
template <typename T>
struct deduced_type;
template<typename T>
void f(T&& ) {
deduced_type<T>::show;
}
int main() {
f(std::string()); // rvalue string
std::string lvalue;
f(lvalue);
const volatile int * const pInt = nullptr;
f(pInt);
}
错误消息:g ++ 4.7.2
错误:嵌套名称说明符中使用的不完整类型deduced_type<std::basic_string<char> >
错误:嵌套名称说明符中使用的不完整类型deduced_type<std::basic_string<char>&>
错误:在嵌套名称说明符中使用的不完整类型deduced_type<const volatile int* const&>
和clang ++
错误:未定义模板的隐式实例化deduced_type<std::basic_string<char> >
错误:未定义模板的隐式实例化deduced_type<std::basic_string<char> &>
错误:未定义模板的隐式实例化deduced_type<const volatile int *const &>
例如,note / info消息还包含两个编译器的f
类型
在void f(T&&) [with T = std::basic_string<char>]
实例化中void f(T&&) [with T = std::basic_string<char>]
这很丑,但很有效。
让编译器向您展示变量的类型(可能是在一个回合的方式);
T parameter;
....
void f(int x);
...
f(parameter);
编译器应该抱怨“T”不能转换为int,假设它实际上不能。
从Ali的答案触发编译器诊断的一种稍微简洁的方法是使用删除的函数。
template <typename T>
f(T&&) = delete;
int main() {
const volatile int * const pInt = nullptr;
f(pInt);
return 0;
}
使用GCC 8.1.0,您将获得:
error: use of deleted function 'void f(T&&) [with T = const volatile int* const&]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.