简体   繁体   中英

Is there a way to store argument's type from templated method at compile time?

I got a weird one. I am trying to find a way to store every templated method's argument type to make it avaiable to class' users. A simple example may be:

template <typename... Ts>
struct Types {};

template <typename... Lhs, typename... Rhs>
constexpr auto operator+(Types<Lhs...>, Types<Rhs...>) {
    return Types<Lhs..., Rhs...>{};
}

class User {
public:

    template <typename Event, typename... New, typename... Old>
    void run(const Event& event) {
        // Something along the lines of:
        types_<New...> = types_<Old...> + Types<Event>{};

        /* Do stuff.. */
    }


private:

    template <typename... T>
    static constexpr Types<T...> types_{};

};

I'm trying to store every Event type from each generated run() method, basically I'm looking for the variadic template's arguments <T...> form the types_ attribute. Is this even allowed by the language?

PS The Types struct is just a failed attempt to hopefully makes the intent of the question clear, any other solution would be more than welcome.

This reminded me of TypeList template structure which has Head and Tail elements

#include <iostream>
#include <typeinfo>    

// List declaration
template <typename... Types>
struct TypeList;

//default specialization
template <typename H, typename... T>
struct TypeList<H, T...>
{
    using Head = H;
    using Tail = TypeList<T...>;
    static const int Length = 1 + sizeof...(T);   
};

//empty list specialization
template<>
struct TypeList<> 
{
    static const int Length = 0;
};

// add element to the top
template<typename H, typename TL>
struct Cons;

template<typename H, typename... Types>
struct Cons<H, TypeList<Types...>>
{
    using type = TypeList<H, Types...>;
};

// concat two TypeLists
template<typename TL1, typename TL2>
struct Concat;

template<typename... Ts1, typename... Ts2>
struct Concat<TypeList<Ts1...>, TypeList<Ts2...>>
{
    using type = TypeList<Ts1..., Ts2...>;
};

// print TypeList
template<typename TL>
void printTypeList(std::ostream& os)
{
    os << typeid(typename TL::Head).name() << '\n';
    printTypeList<typename TL::Tail>(os);
}

template<>
void printTypeList<TypeList<>>(std::ostream& os) {}

int main()
{
    using TL1 = TypeList<double, float, int, char>;
    using TL2 = TypeList<bool, int, bool>;
    using TL3 = Cons<int, TL2>::type;
    using TL4 = Concat<TL1, TL3>::type;

    printTypeList<TL4>(std::cout);
    return 0;
}

UPD I tried to impliment TypeList strategy to your problem but the best I can do to put all types at run-time into std::string...

#include <iostream>
#include <typeinfo>
#include <string>

// List declaration
template <typename... Types>
struct TypeList;

//default specialization
template <typename H, typename... T>
struct TypeList<H, T...>
{
    using Head = H;
    using Tail = TypeList<T...>;
};

//empty list specialization
template<>
struct TypeList<> {};

template<typename TL>
void save_type_to_string(std::string& s)
{
    s.append(typeid(typename TL::Head).name()).append("\n");
    save_type_to_string<typename TL::Tail>(s);
}

template<>
void save_type_to_string<TypeList<>>(std::string& s) {}

class User {
public:

    template <typename... Event>
    void run(const Event... event) {  
        save_type_to_string<TypeList<Event...>>(types);
    }
    void print()
    {
        std::cout << types;
    }
private:     
    std::string types;
};



int main()
{
    User u;
    u.run((int) 10, (long) 0.1, (bool) true);

    u.run((int)10, (bool)true);
    u.print();
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM