我一直在玩类型扣除/打印使用模板的代码形式:
#include <iostream>
template <typename T>
class printType {};
template <typename T>
std::ostream& operator<<(std::ostream& os, const printType<T>&)
{
os << "SomeType"; return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const printType<T*>&)
{
os << printType<T>() << "*"; return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const printType<T&>&)
{
os << printType<T>() << "&"; return os;
}
// etc... and can call on a variable through
template <typename T>
printType<T> print(T) { return printType<T>(); }
int main()
{
int a = 7;
int *p = &a;
int &r = a;
//OK: return SomeType*
std::cout << "type of p: " << print(p) << std::endl;
//Hmmmm: returns SomeType <- (no &: can I get around this?)
std::cout << "type of r: " << print(r) << std::endl;
}
我想知道我是否可以获得最后一行返回int&
,即:
(i)让函数模板print将其参数的类型推导为int&
,或者以某种方式解决它应该在我传递它时返回printType<T&>
;或
(ii)由于变量传递给函数的方式,这是否是不可避免的。
通过改变印刷形式或使用其他模板技巧,有没有办法解决这个问题?如果解决方案存在,我更喜欢非C ++ 0x,但总是很高兴看到将来可以提供哪些捷径(如果还没有)。
答案 0 :(得分:10)
没有办法解决这个问题。表达式p
,其中p
命名引用,始终具有引用引用的类型。没有表达式具有类型T&
。因此,您无法检测表达式是否源自引用。
使用C ++ 0x也无法做到这一点。 C ++的一个深层原则是没有具有引用类型的表达式。您可以编写decltype(r)
以获取r
个名称的类型,而不是表达式r
具有的类型。但你不能写print(r)
,除非print
当然是一个宏,但我不明白为什么你会走那条可怕的道路。
答案 1 :(得分:1)
我接受了我之前所说的话。我想我可能有一种方法可以用纯c / c ++来完成这项工作,尽管它非常混乱。你会 需要将指针传递给你的函数......
即。 bool hello_world(std :: string&amp; my_string,const std :: string * const my_string_ptr){
bool hello_world(std :: string my_string,const std :: string * const my_string_ptr){
如果你现在测试了
if(&amp; my_string == my_string_ptr)
如果var通过引用传递,它将评估 true ,如果通过值传递,则评估为false。
当然,在所有功能中加倍变量可能是不值得的......
约翰内斯是对的...不是纯粹的c ++。但你可以做到这一点。诀窍是作弊。使用像perl这样的嵌入式脚本语言来搜索你的源代码。这是一个嵌入式perl模块:
http://perldoc.perl.org/perlembed.html
将函数名称,变量名称和源位置传递给它,然后使用正则表达式查找变量并检查其类型。实际上,对于您的代码来说,这可能是一个更好的解决方案,假设您总是会有一个方便的源代码。
我会稍微发布这个基本方法的功能......要照顾一些上午的工作! :)
即使您不想分发源代码,也可以创建某种打包函数/ var数据文件,您可以通过@运行时解析它并获得相同的结果。
修改1
例如......使用Perl Embed教程中的# I32 match(SV *string, char *pattern)
函数,您可以执行以下操作:
bool is_reference(const char * source_loc, const char * function_name,
const char * variable_name) {
std::ifstream my_reader;
char my_string[256];
SV * perl_line_contents;
bool ret_val = false;
char my_pattern [400]=strcat("m/.*",function_name);
my_pattern=strcat(my_pattern, ".*[,\s\t]*");
my_pattern=strcat(my_pattern, variable_name);
my_pattern=strcat(my_pattern, "[\s\t]*[\(,].*$");
my_reader.open(source_loc.c_str());
while (!my_reader.eof()) {
my_reader.getline(my_string,256);
sv_setpv(perl_line_contents,my_string);
if(match(perl_line_contents,my_pattern)) {
ret_val= true;
}
}
return ret_val;
}
......有......两种方法(见上文更新)。
答案 2 :(得分:1)
您可以将SFINAE用于整数类型或任何可以通过“0”转换的方式:
template <typename T>
class is_reference
{
struct yes { char a, b; };
typedef char no;
template <typename U> static no test(T y) { }
template <typename U> static yes test(...) { }
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
#include <iostream>
struct not_constructable_from_int {};
struct constructable_from_int { constructable_from_int(int x) { } };
int
main()
{
std::cout << is_reference<int>::value << std::endl;
std::cout << is_reference<int&>::value << std::endl;
std::cout << is_reference<not_constructable_from_int>::value << std::endl;
std::cout << is_reference<not_constructable_from_int&>::value << std::endl;
std::cout << is_reference<constructable_from_int>::value << std::endl;
std::cout << is_reference<constructable_from_int&>::value << std::endl;
}
请注意,测试基本上是“您可以致电test<T>(0)
”,如果T
是参考或,如果T
只是{您无法从0
转换的课程。不幸的是,您可以随时致电test<T>(T())
,这让我感到惊讶(即使T
是int
)。
正如您所看到的那样,您是否愿意从int
开始构建类型,然后测试会对它们起作用,考虑到test<T>(T())
结果,这真的让我感到困惑......