Форум программистов, компьютерный форум CyberForum.ru

непонятная конструкция, шаблоны - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 4.69
LosAngeles
Заблокирован
30.07.2011, 17:28     непонятная конструкция, шаблоны #1
столкнулся со странной конструкцией
C++
1
template<typename C> static One test(int C::*);
в
C++
1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
class IsClassT {
  private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template<typename C> static One test(int C::*);
    
    template<typename C> static Two test(...);
  public:
    enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };
    enum { No = !Yes };
};
в упор не понимаю, что значит int C::*
видел объяснения на русском, на инглише, что это мол какой-то указатель на член, всё равно не догоняю. Может кто-нибудь доходчиво объяснить или хотя привести примеры зачем это нужно ну кроме как здесь? Всё остальное понятно, мне бы этот момент главное прояснить. Заранее спасибо
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.07.2011, 17:28     непонятная конструкция, шаблоны
Посмотрите здесь:

C++ Конструкция if..
C++ конструкция
C++ Конструкция
Что за конструкция? C++
C++ шаблоны классов: непонятная ошибка в одном из методов класса
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
asics
Freelance
Эксперт C++
 Аватар для asics
2838 / 1775 / 144
Регистрация: 09.09.2010
Сообщений: 3,842
30.07.2011, 17:36     непонятная конструкция, шаблоны #2
Из Шилдта:
Как правило, операторы, связаные с указателями на члены класса, применяються в исключительных ситуациях. В повседневном программирование они обычно не используються.
Я это к тому, что пока тебе не попадется вот такая "исключительная" ситуация, ты и не поймешь для чего они.(имхо, конечно)
LosAngeles
Заблокирован
30.07.2011, 17:40  [ТС]     непонятная конструкция, шаблоны #3
а это какая именно из его книг(и глава желательно). Там подробно написано про это явление? Хотелось бы знать, что это за зверь ну на случай, вдруг если сам захочу придумать "исключительную ситуацию"
ValeryLaptev
Эксперт C++
1005 / 784 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
30.07.2011, 17:48     непонятная конструкция, шаблоны #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
LosAngeles, смотри сюда:


Дело в том, что указатель на метод существенно отличается по типу от обычного указателя на функцию, даже если прототипы функции и метода внешне идентичны. Вспомним, как определяется указатель на функцию
C++
1
тип (*имя-указателя)(спецификация параметров);
Для сокращения записи применяют обычно оператор typedef. Объявление
C++
1
typedef тип (*тип-указателя)(спецификация параметров);
вводит новое имя типа. После этого указатель на функцию можно объявлять как
C++
1
тип-указателя имя-указателя;
Указателю присваивается адрес функции. В С++ разрешается присваивать адрес функции
либо явно задавая операцию получения адреса,
C++
1
имя-указателя = &имя-функции;
либо неявно
C++
1
имя-указателя = имя-функции;
В последнем случае имя функции неявно преобразуется в адрес.

Вызов функции через указатель выполняется опять же либо так:
C++
1
(*имя-указателя)(аргументы);
либо в более простой форме,
C++
1
имя-указателя(аргументы);
которая эквивалентна предыдущей
Рассмотрим несколько простых примеров. Допустим, у нас объявлен указатель на функцию
C++
1
int (*pf)(void);
Этому указателю можно присвоить адрес любой функции с таким же прототипом, в том числе и библиотечной. Например, такой прототип имеет функция-генератор случайного числа rand(), который прописан в заголовке библиотеки <cstdlib>.
C++
1
2
3
4
5
int f1(void) { return 1; } 
extern “C” int f2(void) { return 2; }
pf = f1;    cout << pf() << endl;               // вызов f1()
pf = f2;    cout << pf() << endl;               // вызов f2()
pf = &rand; cout << pf() << endl;               // вызов rand()
Как видите, спецификация компоновки никак не мешает косвенному вызову. Напишем теперь простой класс
C++
1
2
3
4
5
6
class Constant
{   int value;
   public: 
    Constant(const int &a): value(a) {}
    int get(void) { return value; }
};
Метод get() с виду имеет тот же прототип, что и функции в приведенном выше фрагменте. Однако попытки присвоить адрес метода get() указателю pf компилятор пресекает «на корню». Да и не совсем понятно, как этот адрес задавать. Вариантов два:
 объявить объект и взять адрес метода в объекте;
 не объявлять объект, а приписать префикс класса.
C++
1
2
3
4
// первый вариант
Constant A(5); pf = &A.get();               
// второй вариант
pf = &Constant::get;
Первый вариант вообще неверный: и Visual C++.NET 2003, и Borland C++ Builder 6 сообщают, что операцию взятия адреса & так использовать нельзя. Второй вариант – ближе к истине: оба компилятора сообщают только о невозможности выполнить преобразование типов. Попытки прописать преобразование явно — не проходят.
C++
1
2
3
pf = static_cast<int (*)(void)>(&Constant::get);
pf = reinterpret_cast<int (*)(void)>(&Constant::get); 
pf = (int (*)(void))(&Constant::get);
Все эти варианты вызывают ту же ошибку компиляции — невозможность преобразования типов. Таким образом, тип указателя на метод класса кардинально отличается от типа указателя на функцию: адрес метода нельзя присвоить указателю на функцию, даже если внешне их прототипы совпадают. Это становится понятным, если мы вспомним, что нестатические методы получают дополнительный параметр — указатель this.

Аналогично, нельзя присвоить обычному указателю на функцию адрес виртуального метода — в этом случае дело усугубляется еще наличием в составе объекта указателя на таблицу виртуальных методов. А вот со статическими методами картина другая! Статический метод не получает никаких «лишних параметров», поэтому его адрес можно присваивать обычному указателю на функцию без всяких преобразований. Добавим в класс Constant статическое поле и статический метод с нужным нам прототипом:
C++
1
2
3
4
5
6
7
8
class Constant
{   int value;
    static int d;
public: 
    Constant(const int &a): value(a) {}
    int get(void) { return value; }
    static int getd(void) { return d; } // --статический метод
};
Тогда нашему указателю pf можно присвоить адрес статического метода вторым из приведенных выше способов, например:
C++
1
pf = Constant::getd;        // или pf = &Constant::getd;
Префикс, естественно, необходимо писать.
Указатель на метод объявляется по-другому [1-8.3.3] — нужно задать префикс-имя класса:
C++
1
int (Constant::*pm)(void);
Такому указателю можно присваивать адреса обычных и виртуальных методов вторым их показанных выше способов, например
C++
1
pm = &Constant::get;        // или pm = Constant::get;
Адрес статического метода, так же как и адрес обычной функции, такому указателю присвоить нельзя — возникает ошибка трансляции: компилятор сообщает о невозможности выполнить преобразование типов.
И косвенный вызов метода выполняется по-другому — с помощью операции
выбора члена класса .* или ->* [1-5.5].
Несмотря на то, что указатель на член класса является отдельной, независимой от класса переменной, вызов метода по указателю возможен только при наличии объекта, например
C++
1
2
Constant A(5);
cout << (A.*pm)() << endl;
Выражение(A.*pm)() означает следующее: для объекта A вызвать метод, чей адрес записан в указателе pm. Слева от операции .* — объект, справа — указатель на метод. Скобки вокруг выражения A.*pm писать обязательно, так как приоритет операции () вызова функции выше, чем приоритет операции выбора члена класса .*.

В выражении (объект.*указатель) можно заменить часть «объект.» на «указатель->», например
C++
1
2
Constant *pc = new Constant(7);
cout << (pc->*pm)() << endl;
Обратите внимание: в выражении (pc->*pm) слева — обычный указатель на динамический объект, а справа — указатель на метод этого объекта. Это совершенно два разных типа указателя.
Интересно, что в системе Visual C++.NET 2003 размер sizeof(pf) указателя на функцию совпадает с размером sizeof(pm) указателя на член класса и равен 4 байта. А вот система Borland C++ Builder 6 выдает совершенно разные цифры: размер указателя на функцию равен 4 байтам, а размер указателя на метод — 12 байт!
asics
Freelance
Эксперт C++
 Аватар для asics
2838 / 1775 / 144
Регистрация: 09.09.2010
Сообщений: 3,842
30.07.2011, 17:48     непонятная конструкция, шаблоны #5
Герберт Шилдт - Полный справочник по C++.
Цитата Сообщение от LosAngeles Посмотреть сообщение
Там подробно написано про это явление?
К сожелению, не совсем, автор просто дает понять что это такое, не углубляясь.
LosAngeles
Заблокирован
30.07.2011, 18:16  [ТС]     непонятная конструкция, шаблоны #6
ValeryLaptev, спасибо огромное! грамотно всё разложил. Такой бы пост надо в какой-нибудь faq затолкать. Я думал, что знаю о указателях всё до твоего поста оказывается нет...
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
30.07.2011, 18:21     непонятная конструкция, шаблоны #7
можно радоваться, что это уйдет в прошлое с появлением std::function в стандарте
ValeryLaptev
Эксперт C++
1005 / 784 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
30.07.2011, 18:30     непонятная конструкция, шаблоны #8
Цитата Сообщение от LosAngeles Посмотреть сообщение
ValeryLaptev, спасибо огромное! грамотно всё разложил. Такой бы пост надо в какой-нибудь faq затолкать. Я думал, что знаю о указателях всё до твоего поста оказывается нет...
В принципе, если админы-модераторы поддержат, то можно много чего наверху закрепить...
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:45     непонятная конструкция, шаблоны #9
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
В принципе, если админы-модераторы поддержат, то можно много чего наверху закрепить...
Только вот у ТС отсутствует список аргументов, при объявлении указателя на метод... Разве так можно?
LosAngeles
Заблокирован
30.07.2011, 19:56  [ТС]     непонятная конструкция, шаблоны #10
вроде как можно. В g++ работаеет
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
30.07.2011, 19:57     непонятная конструкция, шаблоны #11
Цитата Сообщение от LosAngeles Посмотреть сообщение
роде как можно.
Т.е. это указатель на любой метод класса?
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
30.07.2011, 20:08     непонятная конструкция, шаблоны #12
Цитата Сообщение от LosAngeles Посмотреть сообщение
C++
1
template<typename C> static One test(int C::*);
По-моему это все таки указатель на переменную класса.
LosAngeles
Заблокирован
30.07.2011, 20:25  [ТС]     непонятная конструкция, шаблоны #13
Цитата Сообщение от Deviaphan Посмотреть сообщение
Т.е. это указатель на любой метод класса?
наверно так, если такая терминология уместна. Наверно это неявно преобразуется в int (C::*p)(void) или что-то типа того универсальных указателей ведь нет? Кстати если в FAQ это добавлять надо ещё добавить что спецификатор const обязателен, если метод был с ним объявлен, а спецификация исключений вроде необязательна должна совпадать, у меня по крайней мере так
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
30.07.2011, 20:40     непонятная конструкция, шаблоны #14
Цитата Сообщение от LosAngeles Посмотреть сообщение
Наверно это неявно преобразуется в int (C::*p)(void) или что-то типа того
Нет, не может такого быть.
тык, это разные типы.
LosAngeles
Заблокирован
30.07.2011, 20:47  [ТС]     непонятная конструкция, шаблоны #15
а что тогда можно присвоить р?
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
30.07.2011, 22:08     непонятная конструкция, шаблоны #16
Цитата Сообщение от LosAngeles Посмотреть сообщение
а что тогда можно присвоить р?
Сижу, методом тыка пытаюсь определить - это вообще что?
Арифметические операции к этому p не применяются (ошибка компиляции), оператор разыменования указателя тоже. Присвоить какое-то значение ему невозможно, если вывести это p, то выводится просто 1. Пробую вызывать ф-цию по-разному, не указатель на int, не указатель на функцию типа int(*)() в качестве аргумента неприемлемы (ошибка компиляции). Но сама строка:
C++
1
int C::*p;
компилируется нормально. Вообще странно.
P.S. у меня C - это просто класс.

Добавлено через 2 минуты
Да, оператор () тоже неподходит...

Добавлено через 45 минут
LosAngeles, вот нашел в википедии:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  class MyClass
  {
  public:
    int a;
  };
 
  template< class T >
  T& IncrementIntegerElement( int T::* Element, T& Object )
  {
    Object.*Element += 1;
    return Object;
  }
 
  template< class T >
  T IncrementMyClassElement( T MyClass::* Element, MyClass& Object )
  {
    Object.*Element += 1;
    return Object.*Element;
  }
 
  MyClass Obj;
  int n;
 
  n = ( IncrementIntegerElement( &MyClass::a, Obj ) ).a;
  n = IncrementMyClassElement( &MyClass::a, Obj );
Как и предполагалось, это просто указатель на член класса типа int, просто похоже подобная конструкция используется только с шаблонами (с простым классом некомпилируется).
Bers
Заблокирован
31.07.2011, 06:17     непонятная конструкция, шаблоны #17
Цитата Сообщение от Deviaphan Посмотреть сообщение
Только вот у ТС отсутствует список аргументов, при объявлении указателя на метод... Разве так можно?
2008 студия грязно выругалась.

А так, вапще, указатель на метод мне видится неким фейлом.
Попытка заюзать ООП в качестве функционального ЯП
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
31.07.2011, 07:04     непонятная конструкция, шаблоны #18
Цитата Сообщение от Bers Посмотреть сообщение
А так, вапще, указатель на метод мне видится неким фейлом.
Попытка заюзать ООП в качестве функционального ЯП
Не, не фэйл. Порекомендую ещё раз прочесть Александреску (если после прошлой рекомендации ещё не успели прочитать.) ) про функциональные объекты.


Цитата Сообщение от Kastaneda Посмотреть сообщение
Как и предполагалось, это просто указатель на член класса типа int,
Вероятно, так и есть. Но смысл действа не ясен. Почему там просто указатель на int не передаётся? Ничё не понятно... Если кто понял сакральный смысл этого действа, разъясните тугодуму, плиз.)
LosAngeles
Заблокирован
31.07.2011, 07:15  [ТС]     непонятная конструкция, шаблоны #19
если указатель на инт передавать, то первый вариант будет компилироваться всегда вне зависимости от Т вроде как
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
31.07.2011, 07:19     непонятная конструкция, шаблоны
Еще ссылки по теме:

Конструкция try . catch C++
C++ Интересная конструкция в C++
Конструкция в условии C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
31.07.2011, 07:19     непонятная конструкция, шаблоны #20
Цитата Сообщение от LosAngeles Посмотреть сообщение
если указатель на инт передавать
Для второго варианта, указатель на Т передать.)
Yandex
Объявления
31.07.2011, 07:19     непонятная конструкция, шаблоны
Ответ Создать тему
Опции темы

Текущее время: 03:32. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru