2010-09-24 2 views
6

Я играл вокруг с типом дедукции/печать с использованием шаблонов с кодом вида:Шаблон типа вывод ссылки

#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) печать шаблона функции выводит тип аргумента как int& или как-то получается, он должен вернуть printType<T&>, когда я передаю его r; или
(ii) является ли это неизбежным из-за способа передачи переменной функции.

Есть ли способы обойти это, изменив форму печати или используя какой-либо другой шаблонный обман? Если решения существуют, я бы предпочел не-C++ 0x, но всегда хорошо видеть, какие короткие сокращения, если они еще не будут, доступны в будущем.

ответ

9

Невозможно работать с этим. Выражение p, где p обозначает ссылку, всегда имеет тип, на который ссылается ссылка. Никакого выражения никогда не было типа T&. Таким образом, вы не можете определить, возникло ли выражение из ссылки или нет.

Это также невозможно сделать с C++ 0x. Это глубокий принцип C++, что нет выражений с ссылочным типом. Вы можете написать decltype(r) чтобы получить тип, которого r имена, а не те, которые имеют выражение r. Но вы не сможете написать print(r), если print - это, конечно же, макрос, но я не понимаю, почему вы пошли бы по этой ужасной дороге.

+0

Я предлагаю ему ChEaTs ... смотри ниже. –

1

Я принимаю то, что я ранее сказал назад. Я думаю, у меня может быть способ сделать эту работу в чистом c/C++, хотя и очень грязным способом. Вы бы нужно передать указатель на ваши функции ...

т.е. Их hello_world (станд :: строка & my_string, Const станд :: строка * Const my_string_ptr) {

BOOL hello_world (станд :: строка my_string, Const станд :: строка * Const my_string_ptr) {

если вы сейчас проходят

если (& my_string == my_string_ptr)

Он оценил бы true, если var был передан по ссылке, а false, если он принят значением.

Конечно удвоением переменные во всех ваших функций, вероятно, не стоит ...


Johannes прав ... не в чистом C++. Но вы МОЖЕТЕ это сделать. Хитрость - обмануть. Используйте встроенный язык сценариев, например, perl для поиска источника. Вот встроенный модуль Perl:

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

Pass это имя функции, имя переменной, и расположение источника, а затем использовать регулярное выражение, чтобы найти переменную и проверить его тип. На самом деле это может быть лучшим решением для вашего кода в целом, если вы всегда будете иметь источник.

Я отправлю функцию для этого базового подхода немного ... нужно позаботиться о какой-то утренней работе! :)

Даже если вы не хотите распространять источник, вы можете создать какой-то файл данных упакованной функции/var, который вы могли бы проанализировать через @ runtime и получить эквивалентный результат.


Edit 1

Например ... используя # I32 match(SV *string, char *pattern) функции в учебнике Perl Встроить, вы могли бы сделать что-то вроде:

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

... есть .. . Два способа сделать это (см. выше обновление).

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).

Как вы можете увидеть, если вы готовы сделать ваши типы constructable от int то тест работает на них, который на самом деле меня смущает, учитывая test<T>(T()) результат ...

Смежные вопросы