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

Инициализация std::tuple переменным числом аргументов - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.89
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 00:38     Инициализация std::tuple переменным числом аргументов #1
Добрый вечер.
Мне нужно инициализировать объект std::tuple, который является членом некоторого другого шаблонного класса с переменным числом аргументов.
Есть такой код, который, естественно, не компилируется:
C++
1
2
3
4
5
6
7
template<typename...Arg>
struct Base
{
    Base() : NumElems(sizeof...(Arg)), mems(std::make_tuple(Arg...)){}//std::make_tuple(Arg...) - это то, что мне хотелось бы получить в результате)))
    std::tuple<Arg...> mems;
    int NumElems;
};
Предполагается, что Arg - это некоторый список объектов разных классов, которые нужно создать и запихнуть в tuple<Arg...> mems.
У меня есть два вопроса:
1. Собственно, по вышеприведенному коду - как реализовать добавление объектов из списка Args в кортеж?
Например:
C++
1
2
3
4
struct A{};
struct B{};
struct C{};
Base<A,B,C> obj;
Нужно, чтобы при инициализации obj создались три объекта типа A,B и C и добавились в член mems.
2. Есть ли какой-нибудь способ "обхода" пакета Arg наподобие массиву (в цикле, например)?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.07.2013, 00:38     Инициализация std::tuple переменным числом аргументов
Посмотрите здесь:

Функции с переменным числом аргументов C++
Функция с переменным количеством аргументов вызывает out of memory C++
Шаблоны с переменным числом аргументов C++
C++ Шаблон с переменным числом аргументов, и возвращаемое значение функции
C++ Как изменить значение переменной, переданной в списке с переменным числом аргументов
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
29.07.2013, 01:41     Инициализация std::tuple переменным числом аргументов #2
только для типов с constexpr конструтором
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
#include <iostream>
#include <tuple>
 
template<typename... Args>
struct default_tuple_creator;
 
template<class T, typename... Args>
struct default_tuple_creator<T, Args...>
{
    static constexpr std::tuple<T, Args...> value = std::tuple_cat(std::make_tuple(T()), default_tuple_creator<Args...>::value);
};
 
template<class T>
struct default_tuple_creator<T>
{
    static constexpr std::tuple<T> value = std::make_tuple(T());
};
 
template<typename... Args>
std::tuple<Args...> default_constructed_tuple()
{
    return default_tuple_creator<Args...>::value;
}
 
template<typename... Args>
struct Base
{
    Base() 
    : mems(default_constructed_tuple<Args...>())
    , NumElems(sizeof...(Args))
    {}
    
    std::tuple<Args...> mems;
    int NumElems;
};
 
struct A 
{ 
    int a;  
    
    constexpr A() : a(100) {}
};
 
struct B 
{
    int b;
    
    constexpr B() : b(50) {}
};
 
struct C 
{
    int c;
};
 
 
int main()
{
   Base<A, B, C> obj;
 
   std::cout << std::get<0>(obj.mems).a 
             << std::get<1>(obj.mems).b 
             << std::get<2>(obj.mems).c 
             << std::endl;
    
   return 0;
}
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 02:18  [ТС]     Инициализация std::tuple переменным числом аргументов #3
Jupiter, кстати, вот так тоже работает как оказалось:
C++
1
2
3
4
5
6
7
8
template<typename...Arg>
struct Prc
{
    Prc() : mems(std::make_tuple(Arg()...)){}
  
    std::tuple<Arg...> mems;
 
};
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
29.07.2013, 02:28     Инициализация std::tuple переменным числом аргументов #4
Цитата Сообщение от Gorillych Посмотреть сообщение
Нужно, чтобы при инициализации obj создались три объекта типа A,B и C и добавились в член mems.
Я, если честно, не понял, если написать
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename...Arg>
struct Base
{
    Base() : NumElems(sizeof...(Arg)) {}
 
    std::tuple<Arg...> mems;
    int NumElems;
};
 
int main() {
   struct A {};
   struct B {};
   struct C {};
 
   Base<A,B,C> obj;
}
объекты не создадутся или что?
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 02:31  [ТС]     Инициализация std::tuple переменным числом аргументов #5
gray_fox, а они разве добавятся в кортеж? К тому же, структуры A,B и C все-таки не в main будут определяться.
Jupiter
29.07.2013, 02:37
  #6

Не по теме:

Цитата Сообщение от gray_fox Посмотреть сообщение
объекты не создадутся или что?
я огород нагородил.. пора спать

gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
29.07.2013, 02:40     Инициализация std::tuple переменным числом аргументов #7
Gorillych, ну члены mems будут сконструированны (value-initialized вроде), если про это; либо я не понял...

Добавлено через 1 минуту
Цитата Сообщение от Gorillych Посмотреть сообщение
К тому же, структуры A,B и C все-таки не в main будут определяться.
не суть...
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 19:01  [ТС]     Инициализация std::tuple переменным числом аргументов #8
Если кому интересно - ниже реализация гетерогенного контейнера, наподобие boost::any. Можно обходить элементы контейнера наподобие массивам, но в компайл-тайме:
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
namespace static_iterator
{
    template <int... Idx>
    struct index { };
 
    template <int N, int... Idx>
    struct sequence : sequence<N - 1, N - 1, Idx...> { };
 
    template <int... Idx>
    struct sequence<0, Idx...> : index<Idx...> { };
}
 
 
 
struct A {void prnt(){std::cout<<"A\n";} };    
struct B {void prnt(){std::cout<<"B\n";} };    
struct C {void prnt(){std::cout<<"C\n";} };
 
template<typename...Arg>
class HeterogenousContainer
{
public:
    HeterogenousContainer() : 
            number_elems(sizeof...(Arg)), 
            elements(std::make_tuple(Arg()...)){}
 
    std::tuple<Arg...> elements;
 
    template <int... Idx>
    void process(static_iterator::index<Idx...>)
    {
         auto aux = { (std::get<Idx>(elements).prnt(), 0) ... };
    }
 
    void process()
    {
        process(static_iterator::sequence<sizeof...(Arg)>());
    }
    
    unsigned int get_number_elements(){return number_elems;}
    
private:
    unsigned int number_elems;
};
int main()
{  
    HeterogenousContainer<A,B,C,A,A,B,C,B,B,C> obj;
    obj.process();
}
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
29.07.2013, 19:26     Инициализация std::tuple переменным числом аргументов #9
Gorillych, я до сих пор не понял, чем
C++
1
2
3
HeterogenousContainer() : 
            number_elems(sizeof...(Arg)), 
            elements(std::make_tuple(Arg()...)){}
отличается от
C++
1
2
HeterogenousContainer() : 
            number_elems(sizeof...(Arg)) {}
?
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
29.07.2013, 19:32     Инициализация std::tuple переменным числом аргументов #10
Цитата Сообщение от Gorillych Посмотреть сообщение
C++
1
2
3
HeterogenousContainer() : 
    number_elems(sizeof...(Arg)), 
    elements(std::make_tuple(Arg()...))
gray_fox, ничем

Gorillych, если уж делаешь список инициализации то инициализируй поля в том порядке, в котором они объявлены в классе т.е.
C++
1
2
3
HeterogenousContainer() : 
    elements(std::make_tuple(Arg()...)),
    number_elems(sizeof...(Arg))
хотя тут это особой роли не играет, но лучше всегда придерживаться этого
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 19:34  [ТС]     Инициализация std::tuple переменным числом аргументов #11
gray_fox, ну как же. Я чего хотел добиться: в параметрах шаблона HeterogeneousContainer мы указываем список объектов классов, которые мы бы хотели добавить в контейнер. Далее в списке инициализации мы в кортеж добавляем экземпляры объектов перечисленных классов. Если убрать elements(std::make_tuple(Arg()...)), то кортеж будет пустой. Это получается что-то вроде:
C++
1
std::vector<boost::any> obj;
только полностью в компайле и обход поэлементный тоже в компайле.

P.S. Попробуйте скомпилировать c elements(std::make_tuple(Arg()...)) и без
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
29.07.2013, 19:39     Инициализация std::tuple переменным числом аргументов #12
Gorillych, И? https://ideone.com/3bdwJx
Отличий никаких, просто потому, что в кортеже все аргументы будут созданы, используя дефолтный конструктор, ровно это же делает и ваша конструкция.
Это, не то что вы сказали, это
C++
1
std::vector<boost::variant<A, B, C>>
, any тут ни при чем.
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 19:42  [ТС]     Инициализация std::tuple переменным числом аргументов #13
ForEveR, хм....
У меня не компилится почему-то
З.Ы. Все нормально))) Не то делал. Получается, действительно не нужно. Это очень даже хорошо
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
29.07.2013, 19:44     Инициализация std::tuple переменным числом аргументов #14
Цитата Сообщение от Gorillych Посмотреть сообщение
то кортеж будет пустой
Да нет... если надо "пустой", то что-нибудь вроде
C++
1
std::tuple<boost::optional<Arg>...> mems;
тогда разница будет между
C++
1
mems()
и
C++
1
mems(Arg()...)
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 19:48  [ТС]     Инициализация std::tuple переменным числом аргументов #15
gray_fox, да, понял.

Добавлено через 3 минуты
gray_fox, а вот интересно: если у структур A B C будут конструкторы не по умолчанию, с параметрами, как тогда быть?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
29.07.2013, 19:49     Инициализация std::tuple переменным числом аргументов #16
Gorillych, Тогда, так как сделали вы +-.
Gorillych
14 / 14 / 1
Регистрация: 04.07.2013
Сообщений: 76
29.07.2013, 19:50  [ТС]     Инициализация std::tuple переменным числом аргументов #17
ForEveR, т.е. здесь уже явно нужен будет make_tuple, да?
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
29.07.2013, 19:54     Инициализация std::tuple переменным числом аргументов #18
Gorillych, эмм, наверное так
C++
1
2
template<typename ...Other>
Base(Other && ...other) : mems(std::forward<Other>(other)...) {}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.07.2013, 19:55     Инициализация std::tuple переменным числом аргументов
Еще ссылки по теме:

C++ Функция с переменным кол-вом аргументов char vs int
C++ GCC и функции с переменным числом аргументов
C++ Как пройтись по всем типам std::tuple

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

Или воспользуйтесь поиском по форуму:
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
29.07.2013, 19:55     Инициализация std::tuple переменным числом аргументов #19
Gorillych, Можно и конструктор просто вызвать...
Yandex
Объявления
29.07.2013, 19:55     Инициализация std::tuple переменным числом аргументов
Ответ Создать тему
Опции темы

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