Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
AAANDREW
0 / 0 / 0
Регистрация: 10.10.2015
Сообщений: 5
#1

Как можно изменить параметр шаблона (template)? - C++

15.12.2015, 21:26. Просмотров 292. Ответов 4
Метки с++ (Все метки)

есть такие классы:
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
class abstract
{
public:
    virtual int method() = 0; // Допустим
};
 
class A:
    public abstract
{
    int number_int; 
public:
    A() {}
    int method()
    {
        return -1; // Допустим
    }
 
};
 
class B:
    public abstract
{
    float number_float = 5.5; // Допустим
public:
    B() {}
    int method()
    {
        return (number_float + 1) / 2;
    }
};
 
template < class T >
class general
{
    float number_general;
    T object;
public:
    general(int a) : object()
    {
        number_general = a;
    }
    int sum()
    {
        number_general += object.method();
        return number_general;
    }
};
 
int main()
{
    int num = 0;
    cin >> num;
    switch (num)
    {
    case 1: general<A> new_class(5); break; // 1
    case 2: general<B> new_class(5); break; // 2
    default:
        break;
    }
    cout << new_class.sum() << endl;
    system("pause");
    return 0;
}
и вопрос:
т.к. в таком случае (switch) будет ошибка (не будет инициализирован объект), то как сделать так, чтобы в зависимости от выбранного условия, создавался объект с заданными параметрами?

можно было предположить создание указателя:
C++
1
2
3
4
5
6
7
8
switch (num)
    {
    case 1: new_class  = new A(); break; // 1
    case 2: new_class  = new B(); break; // 2
    default:
        break;
    }
general<*new_class> newnew_class(5);
но это точно неправильно
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.12.2015, 21:26
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Как можно изменить параметр шаблона (template)? (C++):

Передача функции как параметр шаблона - C++
Хочу передавать в шаблон любую функцию без параметров и вызывать ее из него. Как это сделать? Не работает, но примерно так должно...

Свой тип как параметр шаблона - C++
Есть вопрос по коду: #include &lt;iostream&gt; #include &lt;memory&gt; #include &lt;vector&gt; using namespace std; template&lt;class T&gt; class...

Можно ли использовать параметр шаблона без типа? - C++
#define TV(OBJ) typeof(OBJ), OBJ template&lt;class T, T obj&gt; class A {/*...*/}; int f (int); A&lt;TV(f)&gt; a; Можно ли сделать...

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

Передать шаблонный класс, как параметр шаблона - C++
нужно не используя stl написать аналог класса list. написал болванку и застрял template&lt;class C&gt; class node{ protected: C *_next; ...

Результат работы функции как параметр шаблона - C++
В старом с++ билдере такое работало, новый clang ругается. template &lt;class T, const IID* piid = &amp;__uuidof(T)&gt; class CComQIPtr { .. ...

4
DiffEreD
1440 / 777 / 95
Регистрация: 21.06.2011
Сообщений: 1,740
Записей в блоге: 2
15.12.2015, 22:17 #2
Ну, самое простое что в голову приходит, это делать нужную работу внутри веток case:
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
template <typename T>
int work(general<T>& gnr)
{
    return gnr.sum();
}
 
int main()
{
    int num = 0;
    cin >> num;
    switch (num)
    {
    case 1:
    {
        general<A> new_class(5);
        cout << work(new_class) << endl;
        break;
    }
    case 2:
    {
        general<B> new_class(5);
        cout << work(new_class) << endl;
        break;
    }
    default:
        break;
    }
}
0
Mr.X
Эксперт С++
3060 / 1705 / 265
Регистрация: 03.05.2010
Сообщений: 3,867
15.12.2015, 22:24 #3
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
68
69
70
71
72
73
74
#include <iostream>
 
class T_abstract
{
public:
    virtual int method() = 0; 
};
 
class A:
    public T_abstract
{
    int number_int; 
public:
    A() {}
    int method()
    {
        std::cout   <<  'A'
                    <<  std::endl;
        return -1; 
    }
 
};
 
class B:
    public T_abstract
{
    float number_float = 5.5; 
public:
    B() {}
    int method()
    {
        std::cout   <<  'B'
                    <<  std::endl;
 
        return (number_float + 1) / 2;
    }
};
 
template < class T >
class T_general
{
    float number_general;
    T object;
public:
    T_general(int a) : object()
    {
        number_general = a;
    }
    int sum()
    {
        number_general += object.method();
        return number_general;
    }
};
 
int main()
{
    char    let     =   0;
 
    for(;;)
    {
        std::cout   <<  std::endl
                    <<  "let = ";
        std::cin    >>  let;
 
        std::cout   <<  (
                            let     ==  'a'
                                ?   T_general<A>(5).sum()
                                :   T_general<B>(5).sum()
                        ) 
        
                    << std::endl;
    }//for
}
0
hoggy
6852 / 3049 / 524
Регистрация: 15.11.2014
Сообщений: 6,922
Завершенные тесты: 1
15.12.2015, 23:49 #4
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от AAANDREW Посмотреть сообщение
и вопрос:
т.к. в таком случае (switch) будет ошибка (не будет инициализирован объект), то как сделать так, чтобы в зависимости от выбранного условия, создавался объект с заданными параметрами?

наиболее оптимальным вариантом было бы пересмотреть дизайн решения.
потому что ваша проблема легко устраняется простыми способами
например, как это показал господин DiffEreD в сообщении #2
тогда проблема исчезнет сама собой.

но если вам критично максимально следовать указанному вами дизайну,
тогда вам может быть сможет помочь паттерн type erasure:

http://rextester.com/DUME68820

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <iostream>
 
class A  // наследоваться от интерфейса не нужно
{
    int number_int; 
public:
    int method()const { return -1; }
};
 
class B
{
    float number_float = 5.5; 
public:
    int method()const { return (number_float + 1) / 2; }
};
 
 
// времени компиляции 
// вычисляем максимальный размер
// указанных типов
template<class A, class B> class max_size
{
    static const size_t sizeA = sizeof(A);
    static const size_t sizeB = sizeof(B);
public:
    static const size_t size = sizeA > sizeB ? sizeA : sizeB;
};
 
 
// не шаблонный!
class general
{
    // паттерн type erasure
    // суть в том, что есть не шаблонный интерфейс
    
    struct ihelper
    {
        virtual ~ihelper(){}
        virtual int sum() = 0;
    };
    
    
    // и шаблонный наследник
    // дергая не шаблонный интерфейс
    // мы приводим в действие функции шаблоно-наследника
    template <class T>
    struct helper : ihelper
    {
        helper(const int a)
            : number_general(a)
        {}
        
        virtual int sum() 
        {
            number_general += object.method();
            return number_general;
        }
        
        float number_general;
        T object;
    };
    
    
    // теперь резервируем буфер под будущего наследника
    // для этого рассчитываем оптимальный размер памяти
    // который может понадобится для его хранения
    enum { size = max_size<helper<A>, helper<B> >::size };
 
    // в качесте этого буфера
    // будем использовать обычный массив
    char type_erasure[ size ];
    
public:
 
       
    // данная функция порождает нужного нам наследника
    // аллоцируя его в нашем буфере
    template<class T> void make(const int a)
    {
        // убедимся, что наш массив достаточно большой
        // что бы вместить в себя наследника
        static_assert(
            sizeof(helper<T>) <= size,
            "ERROR: size helper too big"
        );
        
        // сообщаем, что хотим создать объект
        // не в куче, а в указанном хранилище
        new (type_erasure) helper<T>(a);
    }    
    
    
    // подсчитывает сумму
    int sum()
    {
        // на самом деле она лишь делегирует эту задачу наследнику
        // который сделает для нас всю грязную работу
        
        // но для этого нужно сначала извлечь наследника из нашего буфера
        // в рантайме мы не знаем его точного типа
        // но мы знаем про его не шаблонный интерфейс
        auto* help = reinterpret_cast<ihelper*>(type_erasure);
        
        //и через этот интерфейс можем привести наследника в действие
        return help->sum();
    }
 
    // теперь нам нужен диструктор
    // что бы корректно освободить все захваченные наследником ресурсы
    ~general()
    {
        // для этого извлекаем наследника
        // через его интерфейс
        auto* help = reinterpret_cast<ihelper*>(type_erasure);
        
        // и явным образом дергаем его виртуальный диструктор
        // так как диструктор виртуальный
        // то это приведет к запуску диструктора наследника
        // и тот корректно почистит все за собой
        help->~ihelper();
    }
 
    
};
 
 
// пример использованеия паттерна:
void example_pattern(const int num)
{
    // больше не шаблонный
    general example;
    
    switch (num)
    {
        // теперь в зависимости от 
        // захватываем ресурс: A или B указав стартовые параметры
        case 1: example.make<A>(5); break; 
        case 2: example.make<B>(5); break; 
    }
    
    // и теперь спокойно подсчитываем сумму
    std::cout << "результат для num = "<< num 
        << " : " << example.sum() << "\n";
}
 
int main()
{
    std::cout
        <<"добрый вечер, AAANDREW\n"
        <<"вам может помочь паттерн 'type erasure'\n";
    
    
    example_pattern(1);
    example_pattern(2);
    
}
4
tapochka
40 / 40 / 8
Регистрация: 25.04.2014
Сообщений: 499
16.12.2015, 03:56 #5
немного не по сабжу: а в основе boost.variant тоже type erasure? если кто знает
0
16.12.2015, 03:56
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.12.2015, 03:56
Привет! Вот еще темы с ответами:

Указатель на статический массив как параметр шаблона - C++
Добрый день. Необходимо параметр шаблона сделать указателем и передавать в него указатель на статический массив: template&lt;size_t...

Зачем нужен шаблон как параметр шаблона? - C++
Видел много примеров, но что-то не особо понятно зачем и как это работает.

Использование шаблона template - C++
Попытался использовать шаблон template в функции, но при смене типа переменной появляются проблемы с остальными функциями. Можно ли...

Кортеж с абстрактным типом как параметр шаблона + smart_ptr - C++
Имеем кортеж (std::tuple) с абстрактным типом, параметризуем этим шаблон класса, экземпляров кортежа нигде не создаём. Создаём экземпляры...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru