C++ Appendovanie parameter packs

C++ Appendovanie parameter packs
« kdy: 07. 08. 2021, 01:17:16 »
Kód: [Vybrat]
template <typename... Args>
class PackClass
{
private:
    std::tuple<Args...> values;
public:
    PackClass(Args&& ...args) :
        values(args...)
    {

    }

    template <typename T>
    PackClass<Args..., T> Append(T value)
    {
        return PackClass<Args..., T>(/* riešenie problému */...);
    }
};

Dobrý deň prajem, chcel by som mať šablónu triedy, kde do konštruktora chcem mať možnosť nainjektovať argumenty hociakého typu. Tie argumenty, by sa niekam uložili v (mojom prípade je to tuple, ale kludne sa môžu uložiť hocikam inam) a po zavolaní metódy Append by sa vytvorila rovnaká trieda, do ktorej by sa cez konštruktor pridali uložené hodnoty a zároveň by sa k nim na koniec pridala ďalšia hodnota a spolu s hodnotou by sa dosadil ďalší typ medzi template parametre. Robím si fluent interface do ktrého chcem vkladať lambdy (std::function) rôznych typov a na záver ich všetky aplikovať na nejakú hodnotu, ale žiaľ robím to na platforme kde nemám k dispozícii RTTI* ani C++ 20 (mám len 17ku) takže musím sa trochu uskromniť. V mojom prídklade je problém na treťom riadku od spodu kde sa snažím dosadiť tuple, ale neviem ako ho skonvertovať na parametre konštruktoru a pridať tam ďalší paramter


Re:C++ Appendovanie parameter packs
« Odpověď #1 kdy: 07. 08. 2021, 02:51:17 »
Co třeba něco takového?
Kód: [Vybrat]
#include <any>
#include <vector>

class PackClass
{
private:
    std::vector<std::any> m_values;

public:
    template <typename... Args>
    PackClass(Args&& ...args)
        :m_values(args...)
    {
    }
   
    template<typename T>
    PackClass(std::vector<std::any> values, T value)
        :m_values(std::move(values))
    {
        m_values.emplace_back(value);
    }

    template<typename T>
    PackClass Append(T value) const
    {
        return PackClass(m_values, value);
    }
};


Re:C++ Appendovanie parameter packs
« Odpověď #3 kdy: 07. 08. 2021, 12:52:38 »
Co třeba něco takového?
Kód: [Vybrat]
...

Ďakujem za príklad dosť mi pomohol, keďže v pokročilejšom používaní šablón zatiaľ vôbec nie som doma, ale trošku som ho upravil pre svoje potreby:

Kód: [Vybrat]
#include <iostream>
#include <vector>
#include <utility>
#if __has_include(<any>)
#include <any>

using any = std::any;
#elif __has_include(<experimental/any>)
#include <experimental/any>
using any = std::experimental::any;
#else
static_assert(false, "The std::any type is required");
#endif

template <typename... Args>
class PackClass
{
private:
    std::vector<any> m_values;
public:

    PackClass(Args&& ...args) :
        m_values{ args... }
    {
    }

    template<typename T>
    PackClass(std::vector<any> values, T value) :
        m_values(
            std::move(values)
        )
    {
        m_values.emplace_back(
            value
        );
    }

    template<typename T>
    PackClass<Args..., T> Append(T value) const
    {
        return PackClass<Args..., T>(
            m_values,
            value
        );
    }

    size_t Count() const
    {
        return m_values.size();
    }

    std::vector<any> ToVector() const
    {
        return m_values;
    }

    auto Fetch()
    {

    }
};

int main()
{
    auto object = PackClass{ 3, std::string("TestString"), 'c' };
    auto obj = object.Append(3.5);
    std::cout << obj.Count() << std::endl;
    auto lastItem = std::any_cast<double>(obj.ToVector()[obj.Count() - 1]);
    std::cout << "Test: " << lastItem << std::endl;
    //auto value = obj.Fetch();
    return 0;
}

  • Parameter pack som premiestnil nad classu keďže typovú informáciu budem potrebovať aj pri spracovaní uložených typov
  • V prvom konštruktore pri m_values som vymenil () za {} nakoľko s tými pôvodnými zátvorkami to nešlo skompilovať ani Clangom (verzia C++ 17) ani MSVC (verzia C++ 17)
  • Teraz budem musieť vyriešiť ešte jeden problém: nejako pomocou fold expressions, prejsť typy parameter packu. Následne hodnotu typu std::any pomocou std::any_cast<cleovy_typ> musím skonvertovať na správny typ. A keďže na cielovej platforme nemám k dispozícii RTTI bohužiaľ nemôžem typy porovnávať takto: if (m_values.type() == typeid(nejakyTyp)) budem tie typy musieť získať nejako cez compiler. S tým teraz bojujem. Asi by som si mal objednať nejakú knihu pokročilom používaní šablón, type traitov a metaprogramovaní v C++, lebo toto je momentálne oblasť C++ v ktorej ešte nemám jasno.

Google je tvůj kamarád:

https://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments

Vďaka za odkaz pozriem. Ja som tých prelúskal, už dosť veľa ale priznávam sa bez mučenia že v metaprogramovaní v C++ mám veľké rezervy. Zatiaľ sa to učím googlením a metódou pokus omyl. Templaty sú omnoho ďalej ako generics na ktoré som zvyknutý z vyšších jazykov.

Re:C++ Appendovanie parameter packs
« Odpověď #4 kdy: 07. 08. 2021, 13:12:07 »
Ještě můžeš zvážít std::variant místo std::any (pokud je předem známá množina typů, které tam můžou být) a pak použít std::visit.


Re:C++ Appendovanie parameter packs
« Odpověď #5 kdy: 07. 08. 2021, 16:59:42 »
Nic nezvažuj, jdeš na to dobře, jen je potřeba pochopit co přesně potřebuješ a jak toho docílit. Já bych typování za každou cenu zachoval v tomto případě.

Re:C++ Appendovanie parameter packs
« Odpověď #6 kdy: 07. 08. 2021, 19:09:04 »
Ahojte, any ani variant som nakoniec nepoužil, prepísal som to na tuple a po niekoľko hodinovom googlení a pozeraní príkladov, som sa dopracoval k tomuto riešeniu:

https://pastebin.com/adVfRz8k

Ešte to upravím. walkValues bude niečo spracovávať a spolu s Fetch() bude vracať hodnotu, v reálnom kóde budem do tuple ukladať funkcie.