Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/11: Рейтинг темы: голосов - 11, средняя оценка - 5.00
 Аватар для sendless
8 / 8 / 0
Регистрация: 13.06.2018
Сообщений: 19

Curiously Recurring Template Pattern; CRTP - почему это работает

07.08.2018, 18:31. Показов 2492. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем добрый вечер!

Я задумался над тем почему и как работает CRTP в C++.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 
#include <iostream>
 
using std::cout;
using std::endl;
 
template < class T >
class Base
{
public:
    void interface()
    {
        cout << __PRETTY_FUNCTION__ << endl;
        static_cast< T* >( this )->impl();
    }
 
    static void foo()
    {
        cout << __PRETTY_FUNCTION__ << endl;
        T::bar();
    }
 
private:
    // T t; // will not compile due to the fact that T isn't complete type
};
 
class Derived : public Base< Derived >
{
public:
    void impl()
    {
        cout << __PRETTY_FUNCTION__ << endl;
    }
 
    static void bar()
    {
        cout << __PRETTY_FUNCTION__ << endl;
    }
};
 
int main()
{
    Derived d;
    d.interface();
 
    Base< Derived >::foo();
 
    return 0;
}
 
// pseudo-code of template instantiation
template<>
class Base< Derived >
{
public:
    void interface()
    {
        // ...
        static_cast< Derived* >( this )->impl();
    }
    
    static void foo()
    {
        // ...
        Derived::bar();
    }
};
Поправьте пожалуйста если я не прав/не точен:

Я понимаю что такое неполный тип здесь ...
C++
1
2
3
4
struct Node
{
    Node* next_;
};
... так как next_ это просто адресс какого-то объекта типа T. Во время компиляции система типов проверяет только объявление типа T, адресс которого хранится в указателе, для того чтобы предотвратить операции которые невозможны для этого типа.

CRTP:
1) Компилятор находит выражение Derived d; - в этом время тип Derived ещё не является полным, потому что базовый класс Base< Derived > не инстанциирован.
2) Начинается инстанциирование шаблона Base< Derived >, во время которого шаблонный тип Derived остается неполным.
3) После того как Base< Derived > истанциирован, Base< Derived > становится "полным" типом, Derived при это всё ещё является неполным.
4) После чего происходит создание класса Derived : public Base< Derived >, здесь уже ничего интересного не происходит. Теперь Derived является полным типом.

Получается что Derived находящийся слева от двоеточия и шаблонный тип Derived внутри Base - это два разных типа?

Извините за неточности/грубый подход, у меня мозг сломался пока я пытался понять что происходит. Всё время казалось что некоторого рода рекурсивное отношение происходит между Derived & Base< Derived > в случае наследования. Помогите поставить мозги на место) Спасибо.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
07.08.2018, 18:31
Ответы с готовыми решениями:

Template Method Pattern
Задание называется Template Method Pattern. из параграфа полиморфизм. Вообщем суть задания создать функцию Print() которая бы правильным...

Template Method Pattern
Где можно об этом почитать на русском нормальный материал ? Template Method Pattern

Pattern и template, в чём разница?
Приветствую!!! Сразу к делу, я понимаю, что шаблоны(template) - это образцы, которые могут обработать большинство идентичных задач. А...

8
 Аватар для QuakerRUS
1469 / 1010 / 456
Регистрация: 30.10.2017
Сообщений: 2,799
07.08.2018, 18:49
А оно и не работает. VS2017

Code
1
2
1>d:\work\visual\project1\source.cpp(54): error C2908: явная специализация; уже создан экземпляр "Base<Derived>"
1>d:\work\visual\project1\source.cpp(67): error C2766: явная специализация; уже имеется определение "Base<Derived>"
0
07.08.2018, 18:59

Не по теме:

Цитата Сообщение от QuakerRUS Посмотреть сообщение
А оно и не работает. VS2017
то что ниже 50й строки не входит в исходник :)

0
 Аватар для QuakerRUS
1469 / 1010 / 456
Регистрация: 30.10.2017
Сообщений: 2,799
07.08.2018, 19:23
Max Dark, похоже, что кто то пытался нарисовать вручную (или через какое то ПО?) инстанциирование шаблона, спасибо.

Цитата Сообщение от sendless Посмотреть сообщение
Получается что Derived находящийся слева от двоеточия и шаблонный тип Derived внутри Base - это два разных типа?
Откуда такой вывод? С предыдущими умозаключениями не нашел связи. По логике это один тип как будто бы.
0
Неэпический
 Аватар для Croessmah
18149 / 10733 / 2067
Регистрация: 27.09.2012
Сообщений: 27,031
Записей в блоге: 1
07.08.2018, 19:38
Тип класса становится полным при достижении закрывающей фигурной скобки.
Однако, внутри определения класса есть ряд мест, где этот тип будет полный.
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-
specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
Как видим, base-clause не входит в этот список, а значит в public Base<Derived> тип Derived является неполным.
Цитата Сообщение от sendless Посмотреть сообщение
Получается что Derived находящийся слева от двоеточия и шаблонный тип Derived внутри Base - это два разных типа?
Это один и тот же тип.


Я так понимаю, Вас смущает это:
C++
1
2
3
4
5
void interface()
{
    cout << __PRETTY_FUNCTION__ << endl;
    static_cast< T* >( this )->impl();//Тип T неполный, как же можно использовать функцию-член?
}
Если да, то ответ здесь прост. При инстанцировании Base, функции-члены не инстанцируются. Они будут инстанцированы при использовании, т.е. здесь:
C++
1
2
    Derived d;
    d.interface();//Инстанцируется interface
А в этом месте тип Derived является полным.
2
 Аватар для sendless
8 / 8 / 0
Регистрация: 13.06.2018
Сообщений: 19
07.08.2018, 19:48  [ТС]
QuakerRUS, да, это псевдокод показывающий как предположительно инстанциируется шаблон.

Цитата Сообщение от QuakerRUS Посмотреть сообщение
Откуда такой вывод? С предыдущими умозаключениями не нашел связи. По логике это один тип как будто бы.
Outdated:
Когда уже состоялось создание объекта типа Derived:
Derived : public Base< Derived > - полный тип.
Derived : public Base< Derived > - не полный тип, что-то типа указателя на Derived, т.е. Derived*.

Добавлено через 5 минут
Цитата Сообщение от Croessmah Посмотреть сообщение
Если да, то ответ здесь прост. При инстанцировании Base, функции-члены не инстанцируются. Они будут инстанцированы при использовании, т.е. здесь:
Т.е. полный тип Derived может наследоваться от неполного типа Base< Derived >? Возможно при условии что к моменту инстанцииоривания объекта типа Derived, базовый класс Base< Derived > станет полным типом?
0
Неэпический
 Аватар для Croessmah
18149 / 10733 / 2067
Регистрация: 27.09.2012
Сообщений: 27,031
Записей в блоге: 1
07.08.2018, 19:49
Цитата Сообщение от sendless Посмотреть сообщение
от неполного типа Base< Derived >?
Тип Base<Derived> полный. Почему Вы решили, что он неполный?
0
 Аватар для sendless
8 / 8 / 0
Регистрация: 13.06.2018
Сообщений: 19
07.08.2018, 20:15  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Тип Base<Derived> полный. Почему Вы решили, что он неполный?
Я запутался.
Базовый Base<Derived> - это полный тип, не смотря на то что шаблонный тип <Derived> не полный.
Наследник Derived - тоже полный тип.
При первом вызове метода наследника Derived шаблонный тип <Derived> становится полным типом?
В итоге получается что-то типа:
C++
1
2
3
4
class Derived
{
    Derived d; // won't compile
};
0
Неэпический
 Аватар для Croessmah
18149 / 10733 / 2067
Регистрация: 27.09.2012
Сообщений: 27,031
Записей в блоге: 1
07.08.2018, 20:40
Лучший ответ Сообщение было отмечено sendless как решение

Решение

Цитата Сообщение от sendless Посмотреть сообщение
Не смотря на то что шаблонный тип <Derived> не полный.
Тип Derived не шаблонный. Шаблон у нас Base.
Base инстанцируется с параметром-типом Derived. Base<Derived> будет полным, т.к. мы видим его определение.
Если написать так:
C++
1
2
3
4
template < class T >
class Base;//Объявление шаблонна класса Base
 
class Derived : public Base< Derived >//Здесь Base<Derived> - неполный, т.к. Base объявлен, но не определен.
то ничего не заведется, т.к. Base<Derived> неполный.

Цитата Сообщение от sendless Посмотреть сообщение
C++
1
2
3
private:
    // T t; // will not compile due to the fact that T isn't complete type
};
Так как в public Base<Derived> тип Derived является неполным, то получаем ошибку, если убрать комментарий.
Цитата Сообщение от sendless Посмотреть сообщение
При вызове первого метода на наследника Derived шаблонный тип Derived> становится полным типом?
Тип Derived становится полным после }:
C++
1
2
3
4
class Derived : public Base< Derived >
{
//...
} /*Вот здесь тип Derived станет полным*/ ;
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.08.2018, 20:40
Помогаю со студенческими работами здесь

Visual Studio выдаёт ошибку при вынесении объявления функции с template в .h файл. Без template всё работает
Проект содержит три файла: Source.cpp, arrTreat.h, arrTreat.cpp. Source.cpp: #include &lt;iostream&gt; using std::cout; using...

Почему это работает с Access и не работает с mysql?
Вопрос, собственно, в названии темы. В случае, когда имеет место подключение к mysql получаю сообщение что аргументы имеют неверный тип,...

Почему это не работает?
Почему последний элемент списка переносится на другую строку? Ведь ширина &lt;ul&gt; равно сумме всех элементов и отступов ...

Почему это не работает?
Здравствуйте, почемуто программа работает не так как хотелось бы вроде всё просто, нужно чтобы то что написано в &quot;menu&quot;...

C++ Почему это не работает?
Помогите пожалуйста разобраться(создать студента и группу используя наследование) Код: #include&lt;iostream&gt; ...


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

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru