30 / 8 / 2
Регистрация: 20.08.2011
Сообщений: 615
1

Реализация шаблонного метода с переменным числом параметров

04.08.2016, 10:15. Показов 2252. Ответов 2
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день!
Не могу придумать, как реализовать метод, позволяющий принимать переменное кол-во аргументов. Чтобы понять что именно требуется, ниже приведен код с комментариями:
C++ (Qt)
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
// Данные статический константный хеш описывает столбцы в таблице из БД Sqlite.
// Ключ - целое число (int)
// Значение - это некая структура вида: { QString name, T type }, где name - это строковое название поля в таблице, а type - тип этого поля. Но тип не просто как название, а именно тип с точки зрения C++, в который можно кастовать переменные
// Естественно данный код не скомпилируется. Сделано, чтобы показать суть.
const QHash<int, FieldData> AbstractTableManager::FIELDS = {
    {AbstractTableManager::ID, {"ID", int}},
    {AbstractTableManager::Title, {"Title", QString}},
    {AbstractTableManager::Address, {"Address", MyObject}},
};
 
template<class T, int fieldId> void AbstractTableManager::load(const T &&callback) // функция для выгрузки данных из БД, принимающая колбек и идентиифкатор поля в качестве параметра шаблона
{
    QSqlQuery query("SELECT " + FIELDS[fieldId].name + " FROM MySyperTable"); // делаем запрос в БД. Название поля запроса берем из статического константного хеша 
    if(query.lastError().isValid()) // провека ошибок. Одинакова для всех методов
    {
        qDebug() << "Описание ошибки";
    }
    else
    {
        while(query.next())
            callback(query.value(fieldId).value<FIELDS[fieldId].type>); // итерируем построчно полученный результат запроса. Данные кастуем в заданный тип и передаем их в колбек (одно поле)
    }
}
 
template<class T, int fieldId1, int fieldId2> void AbstractTableManager::load(const T &&callback) // аналогично методы выше. Только теперь в шаблоне 2 идентификатора
{
    QSqlQuery query("SELECT " + FIELDS[fieldId1].name + "," + FIELDS[fieldId2].name + " FROM MySyperTable"); // конкатенируем названия через запятую (2 поля)
    if(query.lastError().isValid())
    {
        qDebug() << "Описание ошибки";
    }
    else
    {
        while(query.next())
            callback(query.value(fieldId1).value<int>, query.value(fieldId2).value<QString>); // аналогично передаем, только теперь ДВА аргумента колбека
    }
}
template<class T, int fieldId1, int fieldId2, int fieldId3> void AbstractTableManager::load(const T &&callback) // аналогично методы выше. Только теперь в шаблоне 3 идентификатора
{
    QSqlQuery query("SELECT " + FIELDS[fieldId1].name + "," + FIELDS[fieldId2].name + "," + FIELDS[fieldId3].name + " FROM MySyperTable"); // конкатенируем названия через запятую (3 поля)
    if(query.lastError().isValid())
    {
        qDebug() << "Описание ошибки";
    }
    else
    {
        while(query.next())
            callback(query.value(fieldId1).value<int>, query.value(fieldId2).value<QString>, query.value(fieldId3).value<MyObject>); // аналогично передаем, только теперь ТРИ аргумента колбека
    }
}
Из этого кода видно, что данные методы отличаются только количеством переданных параметров в шаблон. А также конкатенацией названий полей и количеством передаваемых аргументов в колбек.
Проблема в том, что количество параметов шаблона должно быть переменным. Может быть как тут в примере, а может быть и 7 и 10. Следовательно, можно ли как-нибудь используя шаблоны с переменным числом параметров записать эту мою функцию на общий случай?
Чтобы одна автоматически делала на этапе компиляции конкатенацию названий полей (они ведь известны на этапе компиляции), и автоматически передавала кастованный результат запроса в колбек.

Конкатенацию строк на этапе компиляции мне вроде понятно как делать - можно взять за основу примеры с вычислением суммы чисел или факториала.
А вот с костованием и передачей результата в функцию обратного вызова я не представляю как делать...
Прошу помочь!

Заранее спасибо.

PS Не смотря на то, что код тут написан на Qt, к самому Qt вопрос отношения не имеет (тут мог быть boost например). Просьба оставить тему в разделе по C++, спасибо.

Добавлено через 7 минут
При написании кастинга результата ошибся, нужно было так:
C++ (Qt)
1
callback(query.value(fieldId1).value<FIELDS[fieldId1].type>, query.value(fieldId2).value<FIELDS[fieldId2].type>);
и аналогично для метода с тремя параметрами.

Кастование в нужный тип происходит в методе value<...>.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.08.2016, 10:15
Ответы с готовыми решениями:

Функция с переменным числом параметров шаблонного типа
Доброго времени суток! Объясню вопрос на примере: пусть есть класс Image(хранит некую информацию об...

Функция с переменным числом параметров находящая максимальный элемент в списке параметров
Написать функцию с переменным числом параметров:Максимальный из элементов в списке параметров,...

Функция с переменным числом параметров, как узнать кличество переданных параметров?
Добрый вечер, можно не использовать int n, а каким то другим способом узнать количество переданных...

В функция с переменным числом параметров.
В функцию с переменным числом параметров поступают слова, конец списка - указатель NULL. Найти и...

2
495 / 209 / 70
Регистрация: 27.05.2016
Сообщений: 557
04.08.2016, 10:41 2
Лучший ответ Сообщение было отмечено [progeR] как решение

Решение

В голову пришли 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
std::string globalStr = "Hello word";
 
template <typename T, std::size_t ... Idx>
void func(T&&)
{
    auto size = sizeof...(Idx);
    std::string s(globalStr.begin(), globalStr.begin()+size);
    std::cout << s << "\n";
};
 
template <typename T, std::size_t ... Idx>
void func2(T&&)
{
    std::initializer_list<std::size_t> il{Idx...};
    for (auto id : il)
        std::cout << globalStr[id];
};
 
int main()
{
    func<int, 1,2,3,4>(1);
    func2<int, 4,3,2,1>(1);
}
0
18822 / 9826 / 2401
Регистрация: 30.01.2014
Сообщений: 17,260
04.08.2016, 11:46 3
[progeR],
Вот такой демопримерчик.
Т.к. мне лень было воссоздавать твое окружение, то написал небольшие заглушки, чтобы это можно было запустить. Разберешься что убрать отсюда, а что добавить, надеюсь:
Кликните здесь для просмотра всего текста
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
#include <tuple>
#include <string>
#include <iostream>
class Query
{
public:
    struct value_type
    {
        template <typename T>
        T value() { return T(); }
    };
 
    value_type value(int i)
    {
        return value_type();
    }
};
 
void callback(int a, double b)
{
    std::cout << a << ' ' << b << std::endl;
}
 
enum FieldId
{
    ID, Title, Address
};
 
template <typename T>
struct FieldType
{
    using field_type = T;
 
    std::string name;
};
 
static const std::tuple<
    FieldType<int>
  , FieldType<double>
  , FieldType<std::string>
>
FIELDS
{
    {"ID"}
  , {"Title"}
  , {"Address"}
};
 
template <FieldId ...Ids>
struct FieldIdSelect {};
 
template <FieldId Id>
void fill_query(std::string & qstr, FieldIdSelect<Id>)
{
    qstr += (std::get<Id>(FIELDS).name);
}
template <FieldId Id, FieldId Next, FieldId ...Ids>
void fill_query(std::string & qstr, FieldIdSelect<Id, Next, Ids...>)
{
    qstr += (std::get<Id>(FIELDS).name + ',');
    fill_query(qstr, FieldIdSelect<Next, Ids...>{});
}
 
template <typename T, FieldId ...Ids>
void load(T && callback, FieldIdSelect<Ids...> s)
{
    Query query;
 
    // fill query
    std::string qstr = "SELECT ";
    fill_query(qstr, s);
    qstr += " FROM MyTable;";
 
    std::cout << qstr << std::endl;
 
    // transfer to callback
    using fields_tuple = decltype(FIELDS);
 
    callback(query.value(Ids).value<
                typename std::tuple_element<Ids, fields_tuple>::type::field_type
             >()...);
}
 
int main()
{
    load(callback, FieldIdSelect<ID, Title>{});
}
http://rextester.com/RYF53802
1
04.08.2016, 11:46
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.08.2016, 11:46
Помогаю со студенческими работами здесь

Функция с переменным числом параметров
Доброе время суток! Решил навести красивость в функции что бы по мимо возврата хеш суммы она еще...

Функция с переменным числом параметров
хелп ми вообще дуб дубом Задание Функция с переменным числом параметров Конкретное задание...

Функция с переменным числом параметров
В функцию с переменным числом параметров поступают символы, конец списка - ноль-символ '\ 0'. Найти...

Функции с переменным числом параметров
Добрый день, уважаемые знатоки С++! Подскажите пожалуйста, что не правильно в моем коде? ...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru