Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
136 / 48 / 2
Регистрация: 31.07.2014
Сообщений: 238
1

Автоматическое выведение типа

06.02.2015, 13:14. Просмотров 1682. Ответов 13
Метки нет (Все метки)

Привет всем. Помогите довести код до ума, никак не могу реализовать следующую идею: в параметре шаблона передаю число и в зависимости от него тайпдефится определённый тип данных:

C++
1
2
3
4
5
6
7
template<uint16_t Address>
class Prop
{
public:
    typedef (Address>0xFF? uint16_t: uint8_t) reg_type;
    void operator<<(reg_type);
    void operator>>(reg_type);
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.02.2015, 13:14
Ответы с готовыми решениями:

Автоматическое выведение типа
У С. Прата встретил вот такой непонятный код const double *f2(const double arr, int n) { ...

Автоматическое понижающее преобразование типа
Не пойму почему так происходит. Компилировал в Code Blocks с MinGW. Переменная типа long без...

Автоматическое объявление объекта произвольного типа
Помогите найти информацию по &quot;Автоматическому объявлению объекта произвольного типа&quot;. Что это...

Возврат объекта шаблонного типа от типа Type из специализации шаблона метода от того же типа
Доброго времени суток, пишу класс содержащий несколько std::set от разных типов, нужно сделать...

13
Модератор
Эксперт С++
9795 / 8357 / 5090
Регистрация: 18.12.2011
Сообщений: 22,347
06.02.2015, 13:27 2
Я бы разнес тип и вывод типа в отдельные классы
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
#include <iostream>
using namespace std;
 
template<class T>
struct A
{
    T value;
};
 
template<class Address>
class Prop
{
public:
    void operator<<(Address a){cout<<a.value<<endl;}
};
int main()
{
    A<short> ai={1};
    Prop< A<short> > pi;
    pi<<ai;
 
    A<char> ac={'w'};
    Prop< A<char> > pc;
    pc<<ac;
 
    cout<<endl;
    system("pause");
    return 0;
}
0
Эксперт С++
8175 / 3774 / 813
Регистрация: 15.11.2014
Сообщений: 8,580
06.02.2015, 13:32 3
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <type_traits>
 
template<uint16_t Address>
class Prop
{
public:
    
    typedef typename std::conditional< 
            Address>0xFF, uint16_t, uint8_t
        >::type
    reg_type;
    
    void operator<<(reg_type);
    void operator>>(reg_type);
0
136 / 48 / 2
Регистрация: 31.07.2014
Сообщений: 238
06.02.2015, 13:34  [ТС] 4
Цитата Сообщение от zss Посмотреть сообщение
Я бы разнес тип и вывод типа в отдельные классы
Не, это не то что нужно. Во-первых Address это не тип, а число. Я хочу, чтобы в зависимости от значения этого числа менялась сигнатура операторов << и >>, при этом объявление Prop выглядело бы Prop<0x10> CONF_reg.
0
Эксперт С++
8175 / 3774 / 813
Регистрация: 15.11.2014
Сообщений: 8,580
06.02.2015, 13:40 5
Лучший ответ Сообщение было отмечено NoobsEnslaver как решение

Решение

В примере #3 забыл скобочки поставить:

исправленная версия:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <type_traits>
 
template<uint16_t Address>
class Prop
{
public:
    
    typedef typename std::conditional< 
            (Address>0xFF), uint16_t, uint8_t
        >::type
    reg_type;
    
    void operator<<(reg_type);
    void operator>>(reg_type);
1
136 / 48 / 2
Регистрация: 31.07.2014
Сообщений: 238
06.02.2015, 13:40  [ТС] 6
Цитата Сообщение от hoggy Посмотреть сообщение
#include <type_traits>
template<uint16_t Address>
class Prop
{
public:
typedef typename std::conditional<
Address>0xFF, uint16_t, uint8_t
>::type
reg_type;
void operator<<(reg_type);
void operator>>(reg_type);
О, вот это то, только нужно Address>0xFF в скобки брать, а то компилятор считает, что это закрывающая скобка А как это работает? Т.к. мне это нужно будет переносить в среду IAR (микроконтроллер программирую) и там может этой либы не оказаться. И еще - как сделать выбор между четырьмя аргументами т.к. на самом деле мне нужна проверка трёх условий Address>0xFF , Address>0x1FF, Address>0x2FF?
0
Эксперт С++
8175 / 3774 / 813
Регистрация: 15.11.2014
Сообщений: 8,580
06.02.2015, 13:46 7
Цитата Сообщение от NoobsEnslaver Посмотреть сообщение
А как это работает?
объясняю на более простом примере:

std::conditional это шаблон, эквивалент которого может иметь вид:

C++
1
2
3
4
5
6
    //--------------------если true - выберет T, иначе - U----------------------------//
    template <bool flag, class T, class U> 
        struct Select { typedef T type; };
 
    template <class T, class U> 
        struct Select<false, T, U> { typedef U type; };

Первый параметр шаблона принимает булевую константу времени компиляции false/true

Если указать true, сработает основной шаблон, и вложенный typedef будет алиасом T

Если указать false, сработает специализация под этот случай, и вложенный typedef будет алиасом U

Следующий код вытаскивает из шаблона этот вложенный алиас:

C++
1
2
3
 std::cout <<"type = "
              << typeid( Select<true, int, float>::type ).name()
              << std::endl;
Рассмотрим внимательнее:

C++
1
Select<true, int, float>::type
Здесь type - это вложенный вовнутрь шаблона, его внутренний typedef

Который в зависимости от первого параметра шаблона будет либо int, либо float
0
136 / 48 / 2
Регистрация: 31.07.2014
Сообщений: 238
06.02.2015, 13:53  [ТС] 8
И в догонку вопрос: а как бы сделать еще вот такую вещь:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<uint16_t Address, typename Access>
class Prop
{
public:
typedef typename std::conditional<
Address>0xFF, uint16_t, uint8_t
>::type
reg_type;
void operator<<(reg_type);
void operator>>(reg_type);
 
void Prop<uint16_t Address, typename Access>::operator>>(Prop<uint16_t Address, typename Access>::reg_type)
{
static_assert(typename Access == typename WriteOnly,"Попытка чтения регистра Write-Only");
}
т.е. ввести параметр Access в шаблон и проверять его на static_assert?
0
Эксперт С++
8175 / 3774 / 813
Регистрация: 15.11.2014
Сообщений: 8,580
06.02.2015, 13:58 9
Далее, мы делаем алиас на результат выбора:

C++
1
2
typedef Select< true, int, float >::type
    reg_type;
Теперь reg_type это тоже самый тип, что вернул нам Select

Теперь возвращаемся к исходному шаблону:

C++
1
2
3
4
typedef typename std::conditional< 
            (Address>0xFF), uint16_t, uint8_t
        >::type
    reg_type;
Если все типы известны заранее, то ключевое слово typename не нужно.

Но в шаблонах ключевое слово typename используется, потому что контекстно-зависимая грамматика
Когда компилятор парсит шаблон, он ещё не знает чем он может быть инстанцирован.
И поэтому, не понимает, что там за ботва в typedef.
(на самом деле все он прекрасно понимает, просто так исторически сложилось).

В общем стандарт требует писать typename для
"вложенных в другой шаблон типов, которые зависят от параметра исходного шаблона"

Добавлено через 3 минуты
Цитата Сообщение от NoobsEnslaver Посмотреть сообщение
static_assert(typename Access == typename WriteOnly,"Попытка чтения регистра Write-Only");
C++
1
2
3
4
//true, если типы одинаковые
enum { is_valid = std::is_same<Access, WriteOnly>::value };
 
static_assert(is_valid,  "Попытка чтения регистра Write-Only");
---------------------------------------------

Шаблон is_same имеет примерно такое устройство:

C++
1
2
3
4
5
6
7
//---------вернет true, если типы одинаковые------//
template <typename T, typename U>
    struct is_same { enum { value = false }; };
 
template <typename T> 
    struct is_same<T,T> { enum { value = true }; };
//------------------------------------------------//
если типы были переданы одинаковые, сработает специализация под этот случай, и значение enum станет true
а иначе отработает основной шаблон, и значение enum будет false.

Все что нам нужно - вытащить вложенный в шаблон enum
1
В астрале
Эксперт С++
8023 / 4780 / 654
Регистрация: 24.06.2010
Сообщений: 10,558
06.02.2015, 13:59 10
NoobsEnslaver, Использовать is_same, раз это тип.
C++
1
static_assert(std::is_same<Access, WriteOnly>::value, "Попытка чтения регистра Write-Only");
2
136 / 48 / 2
Регистрация: 31.07.2014
Сообщений: 238
06.02.2015, 14:05  [ТС] 11
Спасибо парни, выручаете. Последнее - как сделать выбор между четырьмя аргументами т.к. на самом деле мне нужна проверка трёх условий Address>0xFF (на это uint8_t) , Address>0x1FF(на это uint16_t), Address>0x2FF(на это uint32_t)?
0
В астрале
Эксперт С++
8023 / 4780 / 654
Регистрация: 24.06.2010
Сообщений: 10,558
06.02.2015, 14:14 12
Лучший ответ Сообщение было отмечено Ilot как решение

Решение

NoobsEnslaver,
C++
1
2
typename std::conditional<(Address > 0x2FF), uint32_t,
typename std::conditional<(Address > 0x1FF), uint16_t, uint8_t>::type>::type
Собственно: если >0x2FF - uint32_t, если > 0x1FF - uint16_t, в остальных случаях uint8_t.
2
Эксперт С++
8175 / 3774 / 813
Регистрация: 15.11.2014
Сообщений: 8,580
06.02.2015, 14:14 13
Цитата Сообщение от NoobsEnslaver Посмотреть сообщение
Спасибо парни, выручаете. Последнее - как сделать выбор между четырьмя аргументами т.к. на самом деле мне нужна проверка трёх условий Address>0xFF (на это uint8_t) , Address>0x1FF(на это uint16_t), Address>0x2FF(на это uint32_t)?
Вы можете более ясно выразить, что конкретно вам нужно?

(я так понимаю - это явно не то, что вы хотите. Но это пример, как можно описать свои желания)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
    std::cout << "Hello, world!\n";
    
    enum { Address = 0x1FF};
    
    if(Address>0xFF )
        std::cout<< "select uint8_t\n";
    else if(Address>0x1FF )
        std::cout<< "select uint16_t\n";
    else if(Address>0x2FF )
        std::cout<< "select uint32_t\n";
    else
        std::cout<< "error\n";
 
}
вывод: select uint8_t
0
136 / 48 / 2
Регистрация: 31.07.2014
Сообщений: 238
06.02.2015, 14:17  [ТС] 14
Цитата Сообщение от ForEveR Посмотреть сообщение
typename std::conditional<(Address > 0x2FF), uint32_t, typename std::conditional<(Address > 0x1FF), uint16_t, uint8_t>::type>::type
Да, это то что нужно. Большое вам спасибо, пойду тоже всем помогать в разделе "микроконтроллеры"
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.02.2015, 14:17

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

Выведение чисел
Доброго дня! Начал изучать С++, возникла проблема немогу написать программу: введя любое число...

Выведение рекуррентной формулы
Помогите вывести рекуррентную формулу для ряда на фотографии. Если можно, с объяснением.

Выведение всех перестановок
Драсте, я вот все время писал на паскале и мне с трудом дается переход на c++. Не могу сделать и...

Выведение рекуррентной формулы
помогите вывести рекуррентную формулу и посчитать сумму членов ряда, больших заданного числа e....


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

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

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