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

Полная спецификация шаблона в перемешку с SFINAE - C++

Восстановить пароль Регистрация
 
rikimaru2013
C++ Game Dev
 Аватар для rikimaru2013
2133 / 966 / 222
Регистрация: 30.11.2013
Сообщений: 3,224
02.01.2016, 18:49     Полная спецификация шаблона в перемешку с SFINAE #1
Добрый вечер,

код полностью не валидный, но показывает мои искренние старания. Желание написать C++11 generation template class, который бы отвечал следующим заявлиным требованиям:
C++
1
2
3
4
5
 cout << Random<int>::getFromTo( 3, 8 ) << endl;             // Expect int type - value(3..8)
    cout << Random<char>::getFromTo( 0, 255 ) << endl;          // Expect char type - value(0..255)
    cout << Random<bool>::getFromTo( false, true ) << endl;     // Expect bool type - value(false..true)
    cout << Random<float>::getFromTo( 1.3f, 4.4f ) << endl;     // Expect float type - value(1.3f..4.4f)
    cout << Random<Foo>::getFromTo( 2, 10 ) << endl;            // Expect Foo type - x value(2..10)
Задачу можно было бы решить сделав полную специализацию для классов явно указав бы типы
C++
1
2
3
4
5
6
template <typename T>
class Random;
template <>
class Random<float>;
template <>
class Random<double>;
Но это же не true coding - как смешать проверку SFINAE на факт нужно ли в exe данный класс и полную спецификацию, чтобы "научить" рендомить всё включая свои типы.

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
157
158
159
160
161
162
163
#include <iostream>
#include <random>
#include <chrono>
#include <type_traits>
#include <string>
using namespace std;
//////////////////////////////////////////////////////////////////////////
#ifndef OUT_TO_STREAM
 
#define OSTREAM_FRIEND(type_)  \
        template<class T> friend   \
        ::std::basic_ostream<T>&  \
        operator<<(::std::basic_ostream<T>& os, const type_& obj )
#endif
//////////////////////////////////////////////////////////////////////////
class Foo // for test
{
    int _x;
public:
    Foo(const Foo& copy)                        { _x = copy._x;}
    Foo(const int x) : _x(x)                    {}
    OSTREAM_FRIEND( Foo )
    {
        os << obj._x << endl;
        return os;
    }   
};
//////////////////////////////////////////////////////////////////////////
namespace RandomImplementation
{
 
    template <typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
    class RandomImpl
    {
    public:
        typedef T                               RType;
        typedef T                               InnerType;
        typedef long long                       MaxType;
 
        typedef std::uniform_int_distribution<MaxType>  uniform_dist;
        typedef std::default_random_engine      gen_type;
 
        gen_type                                m_generator;
 
 
        static RandomImpl*                      getInstance()
        {
            RandomImpl* singltone = new RandomImpl();
            return singltone;
        }
        RandomImpl() :
            m_generator( std::chrono::system_clock::now().time_since_epoch().count() )
        {
        }
 
        static MaxType getFromTo( const InnerType& from, const InnerType& to )
        {
            RandomImpl* instance = getInstance();
            uniform_dist uid_in_range( from, to );
            return uid_in_range( instance->m_generator );
        }
    };
    //----------------------------------------------------------------------------------------------------------------
    template <typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
    class RandomImpl
    {
    public:
        typedef T                               RType;
        typedef T                               InnerType;
        typedef long double                     MaxType;
 
        typedef std::uniform_real_distribution<MaxType>  uniform_dist;
        typedef std::default_random_engine      gen_type;
 
        gen_type                                m_generator;
 
 
        static RandomImpl*                      getInstance()
        {
            RandomImpl* singltone = new RandomImpl();
            return singltone;
        }
        RandomImpl() :
            m_generator( std::chrono::system_clock::now().time_since_epoch().count() )
        {
        }
 
        static MaxType getFromTo( const InnerType& from, const InnerType& to )
        {
            RandomImpl* instance = getInstance();
            uniform_dist uid_in_range( from, to );
            return uid_in_range( instance->m_generator );
        }
    };
}
//////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------
template <typename T, typename std::enable_if<
    std::is_integral<T>::value &&
    !std::is_same<T, char>::value &&
    !std::is_same<T, bool>::value
                                            >::type* = nullptr>
class Random
{
public:
    typedef T                                   RType;
    typedef T                                   InnerType;
 
    static RType getFromTo( const InnerType& from, const InnerType& to )
    {
        return RandomImplementation::RandomImpl<T>::getFromTo( from, to );
    }
};
//------------------------------------------------------------------------
template <typename T, typename std::enable_if<std::is_same<T, char>::value>::type* = nullptr>
class Random
{
public:
    typedef char                                RType;
    typedef char                                InnerType;
 
    static RType getFromTo( const InnerType& from, const InnerType& to )
    {
        return RandomImplementation::RandomImpl<int>::getFromTo( from, to );
    }
};
//------------------------------------------------------------------------
template <typename T, typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr>
class Random
{
public:
    typedef bool                                RType;
    typedef bool                                InnerType;
 
    static RType getFromTo( const InnerType& from, const InnerType& to )
    {
        return RandomImplementation::RandomImpl<int>::getFromTo( from, to );
    }
};
template <typename T, typename std::enable_if<std::is_same<T, Foo>::value>::type* = nullptr>
class Random
{
public:
    typedef Foo                                RType;
    typedef int                                InnerType;
 
    static RType getFromTo( const InnerType& from, const InnerType& to )
    {
        int x = RandomImplementation::RandomImpl<int>::getFromTo( from, to );
        return Foo(x);
    }
};
 
//////////////////////////////////////////////////////////////////////////
int main()
{
    cout << Random<int>::getFromTo( 3, 8 ) << endl;             // Expect int type - value(3..8)
    cout << Random<char>::getFromTo( 0, 255 ) << endl;          // Expect char type - value(0..255)
    cout << Random<bool>::getFromTo( false, true ) << endl;     // Expect bool type - value(false..true)
    cout << Random<float>::getFromTo( 1.3f, 4.4f ) << endl;     // Expect float type - value(1.3f..4.4f)
    cout << Random<Foo>::getFromTo( 2, 10 ) << endl;            // Expect Foo type - x value(2..10)
}
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.01.2016, 18:49     Полная спецификация шаблона в перемешку с SFINAE
Посмотрите здесь:

Полная форма разветвления C++
C++ Полная остановка программы
Спецификация файла. WTF? C++
C++ Обработка исключений. Спецификация
SFINAE придумайте задание C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
hoggy
5114 / 2115 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
02.01.2016, 19:58     Полная спецификация шаблона в перемешку с SFINAE #2
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Но это же не true coding - как смешать проверку SFINAE на факт нужно ли в exe данный класс и полную спецификацию, чтобы "научить" рендомить всё включая свои типы.
не понятно, что именно не получается.
и зачем так много кода для такой простой задачи.

и зачем вообще нужны все эти шаблоны?
можно же было сделать тупо как то так:
C++
1
2
3
4
5
6
7
    uint32_t GetRandom(const uint32_t a, const uint32_t b);
    int32_t GetRandom(const int32_t a, const int32_t b);
    uint64_t GetRandom(const uint64_t a, const uint64_t b);
    int64_t GetRandom(const int64_t a, const int64_t b);
 
    f32_t GetRandom(const f32_t a, const f32_t b);
    f64_t GetRandom(const f64_t a, const f64_t b);
что бы вкрячить поддержку классов,
можно сделать что-то типа такого:

C++
1
2
3
4
5
6
7
8
9
10
11
template<class T> inline T random(const T& a, const T& b)
{
    static std::default_random_engine rnd_(
        static_cast<unsigned>(
            std::chrono::system_clock::now().time_since_epoch().count()
         )
    );
 
    std::uniform_int_distribution<T> distribution(a, b);
    return distribution(rnd_);
}
соответственно, все, что потребуется от возможных T:
отвечать контракту std::uniform_int_distribution
rikimaru2013
C++ Game Dev
 Аватар для rikimaru2013
2133 / 966 / 222
Регистрация: 30.11.2013
Сообщений: 3,224
02.01.2016, 20:02  [ТС]     Полная спецификация шаблона в перемешку с SFINAE #3
Цитата Сообщение от hoggy Посмотреть сообщение
все, что потребуется от возможных T:
отвечать контракту std::uniform_int_distribution
так код и писался, чтобы пофиксить это добавить возможность

Random<char> которую не подерживает uniform_int_distribution
и темболее Random<float> для которой надо uniform_real_distribution.

Ну вот горит желание предоставить функционал при это не "рассказывать" внутрености, что для float и Int разные поля, а для char вообще испобльзуйтеся int преобразованый в char.
hoggy
5114 / 2115 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
02.01.2016, 20:41     Полная спецификация шаблона в перемешку с SFINAE #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
так код и писался, чтобы пофиксить это добавить возможность
Random<char> которую не подерживает uniform_int_distribution
и темболее Random<float> для которой надо uniform_real_distribution.
Ну вот горит желание предоставить функционал при это не "рассказывать" внутрености, что для float и Int разные поля, а для char вообще испобльзуйтеся int преобразованый в char.

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

есть предожение: я вам сейчас каркас сооружу.
а вы его до ума доведите
(а то я внезапно даже и не в курсе про всякие там char и float.
а оно вон оно как, над пофиксить сэмпл)

Добавлено через 36 минут
http://rextester.com/DDB41931

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
#include <iostream>
 
#include <random>
#include <chrono>
 
#define dT \
    typename std::common_type<T1,T2>::type
 
namespace detailRandom{ 
 
    template<class T> struct property_
    {
        enum { eIS_BOOL = std::is_same<T, bool>::value }; 
        
        //TODO: как насчет wchar_t ???
        enum { eIS_CHAR 
            = std::is_same<T, char>::value 
           || std::is_same<T, unsigned char>::value 
           || std::is_same<T, signed char>::value 
        };
        
        enum { eIS_INTEGRAL = std::is_integral<T>::value && !eIS_CHAR && !eIS_BOOL };
        enum { eIS_FLOATING = std::is_floating_point<T>::value };
        enum { eIS_OTHER    = !eIS_CHAR && !eIS_INTEGRAL && !eIS_FLOATING };
    };
    
    template<class T>
    using for_integer 
        = typename std::enable_if< property_<T>::eIS_INTEGRAL >::type*;
    
    template<class T>
    using for_char 
        = typename std::enable_if< property_<T>::eIS_CHAR >::type*;
    
    template<class T>
    using for_bool
        = typename std::enable_if< property_<T>::eIS_BOOL >::type*;
    
    template<class T>
    using for_floating
        = typename std::enable_if< property_<T>::eIS_FLOATING >::type*;
    
    template<class T>
    using for_other
        = typename std::enable_if< property_<T>::eIS_OTHER >::type*;
    
 
    std::default_random_engine& rnd_()
    {
        static std::default_random_engine gen(
            static_cast<unsigned>(
                std::chrono::system_clock::now().time_since_epoch().count()
             )
        );
        return gen;
    }
    
    
 
} // namespace detailRandom
 
template<class T1, class T2, detailRandom::for_integer<dT> = nullptr> inline
dT random(const T1& a, const T2& b)
{
    std::uniform_int_distribution<dT> distribution(a, b);
    return distribution( detailRandom::rnd_());
}
 
template<class T1, class T2, detailRandom::for_floating<dT> = nullptr> inline
dT random(const T1& a, const T2& b)
{
    std::uniform_real_distribution<dT> distribution(a, b);
    return distribution( detailRandom::rnd_());
}
 
template<class T1, class T2, detailRandom::for_char<dT> = nullptr> inline
dT random(const T1& a, const T2& b)
{
    enum { eIS_SIGNED = std::is_signed<dT>::value };
    
    typedef typename std::conditional< eIS_SIGNED, int, unsigned >::type
        type;
    
    const auto a_ = static_cast<type>(a);
    const auto b_ = static_cast<type>(b);
    return static_cast<dT>(random( a_, b_));
}
 
 
template<class T1, class T2, detailRandom::for_bool<dT> = nullptr> inline
dT random(const T1& a, const T2& b)
{
    const auto a_ = static_cast<int>(a);
    const auto b_ = static_cast<int>(b);
    return static_cast<dT>(random( a_, b_));
}
#undef dT
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    std::cout << "integral: ";
    for(size_t n=0;n<10; ++n)
        std::cout << random(1,9)<<", ";
    std::cout << '\n';
    
    std::cout << "floating: ";
    for(size_t n=0;n<10; ++n)
        std::cout << random(1.0,9.0)<<", ";
    std::cout << '\n';
    
    std::cout << "char: ";
    for(size_t n=0;n<10; ++n)
        std::cout << random('a','g')<<", ";
    std::cout << '\n';
    
    std::cout << "bool: ";
    for(size_t n=0;n<10; ++n)
        std::cout << random(false, true)<<", ";
    std::cout << '\n';
    
}
Yandex
Объявления
02.01.2016, 20:41     Полная спецификация шаблона в перемешку с SFINAE
Ответ Создать тему
Опции темы

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