Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 08.04.20 21:52
Оценка:
#include <iostream>
#include <cstdlib>

using namespace std;

struct A {
    A(int v) : a(v) {}
    int a = 9;
};

template<typename T>
struct B: public T {
    template<typename... Args>
    B(Args... args, int v) : T(forward<Args>(args)...), b(v) {}
    int b;
};

int main()
{
    B<A> b(11, 22);
    cout << b.a << b.b<< endl;
}


Этот код не компилируется. Но если поменять конструктор В на:
    B(int v, Args... args) : T(forward<Args>(args)...), b(v) {}

то все работает.

Почему же в начальном варианте дедукция не срабатывает?

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

prog.cc:26:10: error: no matching constructor for initialization of 'B<A>'
    B<A> b(11, 22);
         ^ ~~~~~~
prog.cc:20:5: note: candidate constructor [with Args = <>] not viable: requires single argument 'v', but 2 arguments were provided
    B(Args... args, int v) : T(forward<Args>(args)...), b(v) {}


Можно ли как то такое починить или это в принципе не должно работать?

Заранее спасибо.
Re: Variadic templates arguments position
От: Videoman Россия https://hts.tv/
Дата: 08.04.20 23:10
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Почему же в начальном варианте дедукция не срабатывает?


Смотрите секцию Explanation. Там, как я понял, как раз ваш случай описывается.
Re[2]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 09.04.20 11:21
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Смотрите секцию Explanation. Там, как я понял, как раз ваш случай описывается.


Ну да, там пишется, что это не работает, но это я и так уже понял. А вот почему и как это обойти, вот вопрос.
Re[3]: Variadic templates arguments position
От: Videoman Россия https://hts.tv/
Дата: 09.04.20 16:17
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Ну да, там пишется, что это не работает, но это я и так уже понял. А вот почему и как это обойти, вот вопрос.


Вы уверены что все компилируется? У вас B параметризуется классом A, который в конструкторе принимает единственный аргумент, а вы туда передаете параметр-пак.
Re[4]: Variadic templates arguments position
От: Videoman Россия https://hts.tv/
Дата: 09.04.20 16:52
Оценка:
Здравствуйте, Videoman, Вы писали:

В любом случае, по ходу здесь typename... Args жадничает и раскрывается в <int, int> , а для v ничего не остается.
Re[5]: Variadic templates arguments position
От: watchmaker  
Дата: 09.04.20 17:13
Оценка:
Здравствуйте, Videoman, Вы писали:

V>В любом случае, по ходу здесь typename... Args жадничает и раскрывается в <int, int> , а для v ничего не остается. :xz:


Определённо стоит прочитать ссылку, которую сами и дали :)
По правилам языка parameter pack в приведённом примере всегда раскрывается в пустой <>. О том, что он раскрывается в пустой к тому же можно догадаться ещё и прочтя сообщение компилятора: ведь он сообщает, что фактических параметров слишком много, а не слишком мало.
Re[5]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 09.04.20 17:13
Оценка:
Здравствуйте, Videoman, Вы писали:

V>В любом случае, по ходу здесь typename... Args жадничает и раскрывается в <int, int> , а для v ничего не остается.


Как раз наоборот — Args раскрывается в пустой пак:

candidate constructor [with Args = <>] not viable: requires single argument 'v', but 2 arguments were provided

Re[4]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 09.04.20 17:14
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Вы уверены что все компилируется? У вас B параметризуется классом A, который в конструкторе принимает единственный аргумент, а вы туда передаете параметр-пак.


http://coliru.stacked-crooked.com/a/9a8c58daedf5db30
Re[6]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 09.04.20 17:15
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>По правилам языка parameter pack в приведённом примере всегда раскрывается в пустой <>.


А может и ссылку на стандарт подскажете
Re[5]: Variadic templates arguments position
От: Videoman Россия https://hts.tv/
Дата: 09.04.20 17:28
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>http://coliru.stacked-crooked.com/a/9a8c58daedf5db30


Не понял, зачем вы используется параметр-пак если у вас всегда только два аргумента?
Re[6]: Variadic templates arguments position
От: Videoman Россия https://hts.tv/
Дата: 09.04.20 17:31
Оценка:
Здравствуйте, watchmaker, Вы писали:

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


То что parameter pack жадный предположил читая вот тут. То что по стандарту параметр-пак тут раскрывется в <> я впервые от вас слышу. А можно ссылку где это описано?
Отредактировано 09.04.2020 17:37 Videoman . Предыдущая версия .
Re[6]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 09.04.20 17:48
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Не понял, зачем вы используется параметр-пак если у вас всегда только два аргумента?


Это просто пример, в рельности должно было бы быть множество классов с разным количеством аргументов. И мысль такая, что мы инициализируем самый верхний класс в цепочке наследования, он откусывает от параметр пака нужные себе аргументы, а оставшийся пак спускает дальше родителю, и так далее.
Re[7]: Variadic templates arguments position
От: Videoman Россия https://hts.tv/
Дата: 09.04.20 19:22
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Это просто пример, в рельности должно было бы быть множество классов с разным количеством аргументов. И мысль такая, что мы инициализируем самый верхний класс в цепочке наследования, он откусывает от параметр пака нужные себе аргументы, а оставшийся пак спускает дальше родителю, и так далее.


Идею понял. Тогда, если watchmaker прав и parameter pack по стандарту настолько щедр, что ничего себе не берет, то вариант у вас только поменять аргументы местами, что бы parameter pack всегда был в конце. Но конечно было бы интересно если бы кто-нибудь разъяснил такое поведение.

P.S. а, вот нашел
Отредактировано 09.04.2020 19:24 Videoman . Предыдущая версия .
Re: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 09:44
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Можно ли как то такое починить или это в принципе не должно работать?

Можно вытащить последний аргумент например так:

template<typename T>
struct identity
{
    using type = T;
};

template<typename... Ts>
struct select_last
{
    using type = typename decltype((identity<Ts>{}, ...))::type;
};

template<typename ...Args>
decltype(auto) get_last(Args&&... args)
{
    return (std::get< sizeof...(Args) - 1 >(std::tie(std::forward<Args>(args)...)));
}




template<typename T>
struct B : public T
{
    template<typename... Args>
    B(Args&&... args, int i) : T(std::forward<Args>(args)...), _v(get_last(std::forward(args))) {}
}


А вот как взять из args все кроме последнего не уверен, что возможно.
Обновление: Хотя наверное и возможно. Упаковать args в std::tuple, убрать последний элемент и распаковать обратно.

Если 'A' принимал бы в конструкторе tuple тогда можно было бы создать кортеж и убрать последний элемент.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Отредактировано 10.04.2020 9:46 _NN_ . Предыдущая версия .
Re[2]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 10:29
Оценка: 6 (1)
Здравствуйте, _NN_, Вы писали:

Такой вариант подойдёт ?
Тут надо немного улучшить , но с std::tie(std::forward<Args>(args)...) не собралось.

#include <type_traits>
#include <utility>
#include <tuple>


template<typename... Types>
decltype(auto) get_last_tuple_element(std::tuple<Types...> tp)
{
    return (std::get<std::tuple_size_v<std::tuple<Types...>> -1>(tp));
}

template <typename T, typename... Args, std::size_t... Is>
constexpr decltype(auto) create_object_impl(std::tuple<Args...> tp, std::index_sequence<Is...>)
{
    return T{ std::get<Is>(tp)... };
}

template <typename T, typename... Args>
constexpr decltype(auto) create_object(Args&&... args)
{
    return create_object_impl<T>(std::tie(args...), std::make_index_sequence<sizeof...(Args) - 1>{});
}


struct A
{
    A() {}
    A(int , int , int) {}
};


template<typename T>
struct B : public T
{
    template<typename... Args>
    B(Args&&... args) : T(create_object<T>(std::forward<Args>(args)...)), _v(get_last_tuple_element(std::tie(args...))) {}

    int _v;
};

int main()
{
    B<A> b1(1);

    B<A> b(1,2,3,4);
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 10.04.20 11:26
Оценка:
Здравствуйте, _NN_, Вы писали:

Супер, спасибо! Но к сожалению не подойдет, проблема в том, что и копи, и мув конструкторы запрещены.

Схема такая, что есть один базовый тяжелый класс и над ним надстраиваются классы миксины, у которых может быть произвольное количество аргументов в конструкторе.
Отредактировано 10.04.2020 11:27 koenjihyakkei . Предыдущая версия .
Re[4]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 11:49
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Здравствуйте, _NN_, Вы писали:


K>Супер, спасибо! Но к сожалению не подойдет, проблема в том, что и копи, и мув конструкторы запрещены.


K>Схема такая, что есть один базовый тяжелый класс и над ним надстраиваются классы миксины, у которых может быть произвольное количество аргументов в конструкторе.


В C++17 не будет ни копирования не перемещения, а будет отложенная материализация:

https://gcc.godbolt.org/z/w-jYHb
struct NonMoveableNonCopyable
{

NonMoveableNonCopyable(int, int, int) {}

NonMoveableNonCopyable(NonMoveableNonCopyable const&)= delete;
NonMoveableNonCopyable(NonMoveableNonCopyable&&) = delete;

NonMoveableNonCopyable& operator=(NonMoveableNonCopyable const&) = delete;
NonMoveableNonCopyable& operator=(NonMoveableNonCopyable&) = delete;

};

NonMoveableNonCopyable f()
{
    return {1,2,3};
}

NonMoveableNonCopyable g()
{
    return f();
}

int main()
{
    auto a = g(); // C++17 (^_^)
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 10.04.20 13:18
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>В C++17 не будет ни копирования не перемещения, а будет отложенная материализация:


Ну вроде и так С++17, а ваш код с запрещенным копи конструктором не компилируется: https://gcc.godbolt.org/z/owCH7y
Re[6]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 13:30
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Здравствуйте, _NN_, Вы писали:


_NN>>В C++17 не будет ни копирования не перемещения, а будет отложенная материализация:


K>Ну вроде и так С++17, а ваш код с запрещенным копи конструктором не компилируется: https://gcc.godbolt.org/z/owCH7y


Ну да, там требуется либо копия либо перемещение.
Надо подумать как передать набор аргументов без вспомогательной функции.

А почему перемещение запрещено ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 13:38
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Здравствуйте, _NN_, Вы писали:


_NN>>В C++17 не будет ни копирования не перемещения, а будет отложенная материализация:


K>Ну вроде и так С++17, а ваш код с запрещенным копи конструктором не компилируется: https://gcc.godbolt.org/z/owCH7y


Кстати компилятор MSVC 16.5 код собирает и похоже как не должен .
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.