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

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

07.08.2018, 18:31. Показов 2411. Ответов 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
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 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
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 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
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 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
Ответ Создать тему
Новые блоги и статьи
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru