Link Subtraction Pattern Type

I played with deduction / print type using templates with form code:

#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; } 

I am wondering if I can return the last line of int& , that is:
(i) printing the function template prints the argument type as int& or somehow it turns out, it should return printType<T&> when I pass it r; or
(ii) whether this is unavoidable due to the way the variable is passed to the function.

Are there any ways to do this by changing the print form or using some other template cheating? If solutions exist, I would prefer non-C ++ 0x, but it's always good to see what short cuts, if not already available, are available in the future.

+6
c ++ c ++ 11 templates
source share
3 answers

Impossible to do this. The expression p , where p denotes a link, always has the type the link refers to. An expression has never been of type T& . Thus, you cannot determine whether an expression has arisen from a link or not.

It is also impossible to do with C ++ 0x. This is a deep C ++ principle that there are no expressions with a reference type. You can write decltype(r) to get the type of the names r , rather than the type that the expression r . But you cannot write print(r) unless print is a macro, but I donโ€™t understand why you would take this terrible road.

+9
source share

I take what I said earlier. I think I might have a way to make this work in pure c / C ++, albeit in a very dirty way. You would need to pass a pointer to your functions ...

i.e. bool hello_world (std :: string and my_string, const std :: string * const my_string_ptr) {

bool hello_world (std :: string my_string, const std :: string * const my_string_ptr) {

if you tested

if (& my_string == my_string_ptr)

It would evaluate true if var was passed by reference, and false if it was passed by value .

Of course, doubling your variables in all of your functions is probably not worth it ...


Johannes is right ... not in pure C ++. But you CAN do it. The trick is to cheat. Use the built-in scripting language, such as perl, to find the source. Here's the perl built-in module:

http://perldoc.perl.org/perlembed.html

Pass it the name of the function, the name of the variable, and the location of the source, and then use the regular expression to find the variable and check its type. In fact, this may be the best solution for your code as a whole, if you always have a source.

I will post a function for this basic approach a bit ... you need to take care of some morning work! :)

Even if you do not want to distribute the source, you can create some kind of packed function data file / var, which you could parse through @runtime and get an equivalent result.


Change 1

For example, using the # I32 match(SV *string, char *pattern) function in the Perl Embed tutorial, you can do something like:

 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; } 

... there are ... two ways to do this (see update above).

+1
source share

You can use SFINAE with built-in types or whatever you can convert from "0" as follows:

 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; } 

Note that the test is basically โ€œyou can call test<T>(0) โ€, which you cannot if T is a reference or if T is just any class that you cannot convert from 0 . Unfortunately, you can always call test<T>(T()) , which surprised me (even if T is int ).

As you can see, are you ready to make your types constructive from int , then a test works on them, which really confuses me with the result of test<T>(T()) ...

+1
source share

All Articles