Тип шаблона удержание ссылки - PullRequest
7 голосов
/ 24 сентября 2010

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

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

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

Ответы [ 3 ]

10 голосов
/ 24 сентября 2010

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

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

1 голос
/ 24 декабря 2012

Вы можете использовать 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()) результат ...

1 голос
/ 24 сентября 2010

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

т.е. bool hello_world (std :: string & my_string, const std :: string * const my_string_ptr) {

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

, если вы сейчас протестировали

if (& my_string == my_string_ptr)

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

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


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

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

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

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

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

Редактировать 1

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...