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[6]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 13:47
Оценка: 6 (1)
Здравствуйте, koenjihyakkei, Вы писали:

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


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


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


Можно перенести тело вспомогательных функций в сам класс и тогда всё собирается:

#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));
}



struct A
{
    A() {}
    A(int, int, int) {}
    A(A const&) = delete;
    A(A&&) = delete;
};


template<typename T>
struct B : public T
{
    template<typename... Args>
    B(Args&&... args) :
        B(std::forward_as_tuple(args...), std::make_index_sequence<sizeof...(Args) - 1>{}, get_last_tuple_element(std::tie(args...)) )
    {
    }

    int _v;

private:
    template<typename... Args, std::size_t... Is>
    B(std::tuple<Args...> tp, std::index_sequence<Is...>, int v) : T(std::get<Is>(tp)...), _v(v)
    {

    }
};

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

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

_NN>А почему перемещение запрещено ?


Много POD данных, которые по сути копируются, и есть данные, которые в принципе нельзя скопировать без приседаний.
Re[7]: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 10.04.20 14:36
Оценка:
Здравствуйте, _NN_, Вы писали:

Это уже интереснее, мысль понятна, спасибо. Если обернуть еще макросами, то можно сократить количество вспомагательного кода, тогда менее верятно, что меня с этим пошлют А то эти struct B не только я буду писать.
Re[8]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 10.04.20 14:50
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

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


K>Это уже интереснее, мысль понятна, спасибо. Если обернуть еще макросами, то можно сократить количество вспомагательного кода, тогда менее верятно, что меня с этим пошлют А то эти struct B не только я буду писать.


Полагаю можно поиграться с кодом и упростить, может с CRTP или другим подходом.
Всё же, если не критично ставить параметры класса вначале, а не в конце, то это будет лучшим решением.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Variadic templates arguments position
От: koenjihyakkei Россия  
Дата: 12.04.20 23:18
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

Если кому интересно, поигрался с версией от _NN_ и пришел к следующему варианту. Буду благодарен если кто подскажет, как можно улучшить.
Единственно у него есть один недостаток и возможно достаточно серьезный: не работает implicit conversion — компиляция падает с ошибкой "recursive template instantiation exceeded maximum depth", что в принципе логично.
То есть если конструктор ждет unsigned, а передается 123, а не 123u, то ошибка.
Причем если не менять параметр template-depth (по умолчанию он 1024) то компиляция может занимать приличное время. В общем неприятная ситуация получается.

http://coliru.stacked-crooked.com/a/facf23243c3cdbeb

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


#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define MIXIN_INIT() T(std::get<Is>(tp)...)

#define MIXIN_CONSTRUCTOR(MIXIN, ...) \
    static constexpr size_t ArgsNum = VA_NARGS(__VA_ARGS__); \
    template<typename... Args>  \
    MIXIN(Args&&... args) : MIXIN(std::forward_as_tuple(args...), std::make_index_sequence<ArgsNum>{} ) {} \
    \
    template<typename... Args, std::size_t... Is> \
    MIXIN(std::tuple<Args...> tp, std::index_sequence<Is...>) : \
    MIXIN(tp, std::make_index_sequence<sizeof...(Args) - ArgsNum>{}, std::get<sizeof...(Args) - ArgsNum + Is>(tp)... ) {} \
    \
    template<typename... Args, std::size_t... Is> \
    MIXIN(std::tuple<Args...> tp, std::index_sequence<Is...>, __VA_ARGS__)


template<typename... Args>
void print(Args... args) {
    ((std::cout << ' ' << args), ...) << std::endl;
}

struct Base
{
    Base(int v1, const char* v2) : a(v1), b(v2) {}
    Base(Base const&) = delete;
    Base(Base&&) = delete;
    
    int a;
    const char* b;
};

template<typename T>
struct Foo : public T
{
    MIXIN_CONSTRUCTOR(Foo, bool v, float v2) : MIXIN_INIT(), c(v), d(v2) {}

    bool c;
    float d;
};


template<typename T>
struct Bar : public T
{
    MIXIN_CONSTRUCTOR(Bar, char c, float f, uint32_t n) : MIXIN_INIT(), ch(c), fl(f), num(n) {}

    char ch;
    float fl;
    uint32_t num;
};

struct Final : public Bar<Foo<Base>> {
    using Base = Bar<Foo<Base>>;
    using Base::Base;
};

int main()
{
    Foo<Base> f1(1, "hello", true, 1.0f);
    print(f1.a, f1.b, f1.c, f1.d);
    
    Bar<Base> f(1, "hello", 'a', 3.14f, 123u);
    print(f.a, f.b, f.ch, f.fl, f.num);
    
    Final f2(1, "hello", true, 1.24f, 'r', 3.14f, 123u);
    print(f2.a, f2.b, f2.c, f2.d, f2.ch, f2.fl, f2.num);
}
Re[2]: Variadic templates arguments position
От: _NN_ www.nemerleweb.com
Дата: 13.04.20 10:58
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

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


K>Если кому интересно, поигрался с версией от _NN_ и пришел к следующему варианту. Буду благодарен если кто подскажет, как можно улучшить.

K>Единственно у него есть один недостаток и возможно достаточно серьезный: не работает implicit conversion — компиляция падает с ошибкой "recursive template instantiation exceeded maximum depth", что в принципе логично.
K>То есть если конструктор ждет unsigned, а передается 123, а не 123u, то ошибка.
K>Причем если не менять параметр template-depth (по умолчанию он 1024) то компиляция может занимать приличное время. В общем неприятная ситуация получается.

Что-то сложно получилось.
Да ещё и макрос думаю упростить можно.

Кстати, нужно использовать Args&&... , чтобы избежать копирования


template<typename... Args>
void print(Args&&... args) {
    ((std::cout << ' ' << args), ...) << std::endl;
}


P.S.
https://www.walletfox.com/course/cheatsheets_cpp.php
http://rsdn.nemerleweb.com
http://nemerleweb.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.