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

[дизайн и эволюция] провалы в variadic конструкторы - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Вывести 10 самых длинных (по числу символов) предложений http://www.cyberforum.ru/cpp/thread1637394.html
Ребят программисты помогите, понимаю что программа легкая. Но не могу сделать. Текст надо считать из файла.
C++ Найти причины и способы устранения ошибки Во время откладки указатель на число выдает мусор типо -81791524 #include <stdlib.h> #include <time.h> #include <iostream> #include <conio.h> #include <cctype> using::std::cin; using::std::cout; using::std::endl; http://www.cyberforum.ru/cpp/thread1637383.html
Как лучше всего пробежать все элементы контейнера? C++
Речь о следующем. Есть vector. Я хочу пробежать все его элементы, но походу я буду проверять удовлетворяют они определенному условию или нет. Если да, то этот элемент удаляется. Как это лучше всего реализовать?
C++ Найти сумму ряда
Ребят, голову ломаю и никак не осилю. В чем смысл вообще? Я понять формулу даже не могу, не то что уж код написать здесь. Какие-то "-...+". Что это вообще? Помогите кто чем может.
C++ Вычислить произведение отрицательных элементов массива http://www.cyberforum.ru/cpp/thread1637347.html
Приветствую вас дорогие форумчане. Прошу о помощи в изменении программы. В коде предоставленном ниже требуется заменить: рандомный подбор чисел на вводимый. Зарание спасибо! (Текст задания: В одномерном массиве, состоящем из n вещественных элементов, вычислить: 1.) произведение отрицательных элементов массива; 2.) сумму положительных элементов массива, расположенных до максимального элемента....
C++ Реализовать структуру "Student" Создайте программу для ввода и вывода фамилий и оценок студентов. Введите не менее 10 студентов. Отберите студентов, у которых вторая и четвертая оценка 2 подробнее

Показать сообщение отдельно
hoggy
6158 / 2524 / 443
Регистрация: 15.11.2014
Сообщений: 5,583
Завершенные тесты: 1
13.01.2016, 04:36  [ТС]     [дизайн и эволюция] провалы в variadic конструкторы
Часть 3.

способ для 1 параметра шаблона отлично работает.
и это - хорошая новость.

плохая заключается в том,
что это работает только, и только для 1 параметра шаблона.
и не работает для вариадиков.

дело в том, что мы заранее не знаем,
сколько параметров будет у вариадика.

ситуация усугубляется ещё и тем, что их может не быть вообще.
(пустой конструктор, например)

мы не можем просто так взять,
и вычислить тип последнего параметра.
(на самом деле можем, если поприседать вокруг мета-программинга.
но конструкция получится замороченной)

самое ужассное заключается в том,
что мы не можем подмешать параметр,
выводимый по умолчанию после вариадик-пака,
как мы это делали для 1 параметра.
в общем, решение для 1 параметра не сработает в вариадиком
в принципе.
то есть вообще не сработает.


однако решение существует.
и для того, что бы понять, как это работает,
я и сделал такую подробную пошаговую иллюстрацию
для одного параметра.

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

решение проблемы вариадиков заключается в том,
что бы создать дополнительно шаблоно-конструктор с одним параметром.
и тогда все возможные провалы по 1 параметру попрут на него.

к сожалению, мы не сможем порезать шаблон с 1 параметром,
как мы это делали выше. потому что если порежем,
то шаблон вылетит из конкурса,
и мы опять провалимся в вариадик конструктор.

суть решения не в том, что бы порезать шаблон с 1 параметром.
а в том, что бы перенаправить его на нужные нам конструкции.

итак, знакомьтесь с новой техникой с++11:
делегирующие конструкторы:

http://rextester.com/ADMR12889

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
#include <iostream>
#include <cassert>
 
enum eCTOR{ eNONE, eVARIADIC, eONE, eCOPY, eRVALUE };
 
 
namespace detail{
    
    // --- предназначен для решения проблемы 
    // вызовов конструкторов в ситуации, 
    // когда любые аргументы проваливаются 
    // в вариадик-конструкторе
    template<class D, class B> class selector
    {
        typedef typename std::remove_reference<
            typename std::remove_reference<D>::type
        >::type
            derrived_t;
            
        typedef typename std::remove_reference<
            typename std::remove_reference<B>::type
        >::type
            base_t;
 
        enum { 
            eIS_DERRIVED = std::is_base_of<base_t, derrived_t>::value           
        };
 
        enum { eIS_RVALUE = std::is_rvalue_reference<D>::value };
 
    public:
        enum { eCOPY   =  eIS_DERRIVED && !eIS_RVALUE };
        enum { eRVALUE =  eIS_DERRIVED &&  eIS_RVALUE };
        enum { eOTHER  = !eIS_DERRIVED                };
    };
 
    template<class D, class B>
        using for_copy 
            = typename std::enable_if< selector<D,B>::eCOPY>::type*;
 
    template<class D, class B>
        using for_rvalue 
            = typename std::enable_if< selector<D,B>::eRVALUE>::type*;
 
    template<class D, class B>
        using for_other
            = typename std::enable_if< selector<D,B>::eOTHER>::type*;
    
}//namespace detail
 
struct example
{
        #define dRVALUE detail::for_rvalue<A&&, example> = nullptr
        #define dCOPY   detail::for_copy  <A&&, example> = nullptr
        #define dANY    detail::for_other <A&&, example> = nullptr
 
        template<class... Args> 
        example(Args&&... args):m_ctor(eVARIADIC)
            { std::cout << "variadic\n"; }
 
    // --- тоже самое, что вариадик, только для 1 параметра
        template<class A, dANY> 
        example(A&& a):m_ctor(eONE)
            { std::cout << "one\n"; }
 
    // --- перенаправление на констурктор копии
        template<class A, dCOPY> 
            example(A&& rhs): example(static_cast<const example&>(rhs))
            {}
    
    // --- перенаправление на констурктор перемещения
        template<class A, dRVALUE> example(A&& rhs): 
            example(std::move(static_cast<example&&>(rhs)))
            {}
 
        example(const example&):m_ctor(eCOPY)
            { std::cout << "copy\n"; }
    
        example(example&& ):m_ctor(eRVALUE)
            { std::cout << "move\n"; }
 
        #undef dRVALUE 
        #undef dCOPY   
        #undef dANY    
 
    eCTOR m_ctor;
};
 
 
struct der: example
{
    der(const int a):example(a){}
    der(const int a, const int b):example(a,b){}
    der(const der& rhs):example(rhs){}
    der(der&& rhs):example(std::move(rhs)){}
};
 
der rvalue() {  return std::move(der(10)); }
 
int main()
{
    std::cout <<"hello, world\n";
 
    der d1(10,20);
    assert(d1.m_ctor==eVARIADIC);
    
    der d2(10);
    assert(d2.m_ctor==eONE);
 
    der d3 = d1;
    assert(d3.m_ctor==eCOPY);
    
    der d4 = rvalue();
    assert(d4.m_ctor==eRVALUE);
    
}
вот так: немножко там шаблончик, тут макросик,
и вуаля! вариадик взят под контроль.

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

лично я для подобных целей завел библиотеку
под названием "костыль" "workground"
что в переводе на русски, должно означать "обходной путь":

итоговое решение:

http://rextester.com/FUHG59360

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
#include <iostream>
#include <cassert>
 
// =====================================================================================
// =====================================================================================
// =====================================================================================
// весь этот ужас скрыт в библиотеке "workground"
//
// workground.h
//
namespace detail{
    
    // --- предназначен для решения проблемы 
    // вызовов конструкторов в ситуации, 
    // когда любые аргументы проваливаются 
    // в вариадик-конструкторе
    template<class D, class B> class selector
    {
        typedef typename std::remove_reference<
            typename std::remove_reference<D>::type
        >::type
            derrived_t;
            
        typedef typename std::remove_reference<
            typename std::remove_reference<B>::type
        >::type
            base_t;
 
        enum { 
            eIS_DERRIVED = std::is_base_of<base_t, derrived_t>::value           
        };
        
        enum { eIS_RVALUE = std::is_rvalue_reference<D>::value };
 
    public:
        enum { eCOPY   =  eIS_DERRIVED && !eIS_RVALUE };
        enum { eRVALUE =  eIS_DERRIVED &&  eIS_RVALUE };
        enum { eOTHER  = !eIS_DERRIVED                };
    };
 
    template<class D, class B>
        using for_copy 
            = typename std::enable_if< selector<D,B>::eCOPY>::type*;
 
    template<class D, class B>
        using for_rvalue 
            = typename std::enable_if< selector<D,B>::eRVALUE>::type*;
 
    template<class D, class B>
        using for_other
            = typename std::enable_if< selector<D,B>::eOTHER>::type*;
    
    #define dFOR_CONSTRUCTOR_(situation, type_) \
        detail::for_##situation<A&&, type_> = nullptr
    
    #define dWITH_REDIRECT_CONSTRUCTORS(type_)                \
        template<class A, dFOR_CONSTRUCTOR_(copy, type_) >    \
            type_(A&& rhs)                                    \
                : type_(static_cast<const type_&>(rhs))       \
            {}                                                \
                                                              \
        template<class A, dFOR_CONSTRUCTOR_(rvalue, type_) >  \
            type_(A&& rhs)                                    \
                : type_(std::move(static_cast<type_&&>(rhs))) \
            {}                                                \
                                                              \
        template<class A, dFOR_CONSTRUCTOR_(other, type_)>    \
            type_(A&& a)
    
}//namespace detail
 
 
// =====================================================================================
// =====================================================================================
// =====================================================================================
 
// вот это все, что полагается видеть пользователю:
 
enum eCTOR{ eNONE, eVARIADIC, eONE, eCOPY, eRVALUE };
 
struct example
{
    template<class... Args> 
    example(Args&&... args):m_ctor(eVARIADIC)
        { std::cout << "variadic\n"; }
 
    dWITH_REDIRECT_CONSTRUCTORS(example):m_ctor(eONE)
        { std::cout << "one\n"; }
 
    example(const example&):m_ctor(eCOPY)
        { std::cout << "copy\n"; }
 
    example(example&& ):m_ctor(eRVALUE)
        { std::cout << "move\n"; }
 
    eCTOR m_ctor;
};
 
// =====================================================================================
// =====================================================================================
// =====================================================================================
 
// теперь, если пользователь захочет отнаследоваться,
// то ему вообще не обязательно думать о том ужассе
// что на самом деле таится в базовом классе
 
struct der: example
{
    der(const int a):example(a){}
    der(const int a, const int b):example(a,b){}
    der(const der& rhs):example(rhs){}
    der(der&& rhs):example(std::move(rhs)){}
};
 
der rvalue() {  return std::move(der(10)); }
 
int main()
{
    std::cout <<"hello, world\n";
 
    der d1(10,20);
    assert(d1.m_ctor==eVARIADIC);
    
    der d2(10);
    assert(d2.m_ctor==eONE);
 
    der d3 = d1;
    assert(d3.m_ctor==eCOPY);
    
    der d4 = rvalue();
    assert(d4.m_ctor==eRVALUE);
}
здесь ещё могут быть какие то редкие случаи,
которые данный код не учитывает.
например: const rvalue,
ну или volatile какие нибудь.

но это редкие кейсы.
я думаю нет смысла из-за них усложнять и без того
мало мало замороченное клюкало.

к тому же, архитектура selector`a специально ориентирована
на возможные расширения.

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