Forum: PC-Programmierung C++17, Template Parameter-Pack Subset?


von cppbert3 (Gast)


Lesenswert?

Hallo C++17 Gurus,

ich versuche gerade aus einem Parameter-Pack mit Typen
eine minimale Tree-Struktur zu erzeugen (ist für einen hierarchischen 
Daten-Filter)

In jeder Ebene wird aus dem uebergebenem Parameter-Pack der 1. Typ raus 
genommen und der Rest and die darunter liegende Ebene geschoben

das mit dem 1. Typ raustrennen funktioniert aber
an der Beschneidung des Parameter-Packs scheitere ich - meine
skip_first erzeugt ein tuple - aber ich weiss nicht wie
ich den tuple als Parameter-Pack uebergeben kann

jemand einen Tip?

gcc-godbolt: https://gcc.godbolt.org/z/EP637d
1
#include <tuple>
2
#include <vector>
3
#include <type_traits>
4
5
template<typename... Types>
6
using get_first = typename std::tuple_element<0,std::tuple<Types...>>::type;
7
8
template <typename T>
9
struct skip_first{};
10
11
template <typename First, typename... Rest>
12
struct skip_first<std::tuple<First, Rest...>>
13
{
14
  using type = std::tuple<Rest...>;
15
};
16
17
template <typename Container, typename FirstType, typename... RestTypes>
18
struct Sub
19
{
20
    const Container m_c;
21
    Sub(const Container& c):m_c(c){}
22
    using first_type = FirstType;
23
24
    using sub_first_type = get_first<RestTypes...>;
25
    using sub = Sub<Container, sub_first_type, RestTypes.../*[1...]*/>;
26
    sub get_sub() { return Sub(m_c); }
27
};
28
29
template <typename Container, typename... Types>
30
struct Top
31
{
32
    using sub_first_type = get_first<Types...>;
33
    using sub = Sub<Container, sub_first_type, Types.../*[1...]*/>;
34
};
35
36
using container = std::vector<int>;
37
using top = Top<container, int, short, long>;
38
39
static_assert(std::is_same<top::sub::first_type, int>::value, "wrong");
40
// die Test gehen nicht weil ich immer das volle Parameter-Pack weiter reichen
41
#if 0
42
static_assert(std::is_same<top::sub, Sub<container, int, short, long>>::value, "wrong");
43
44
static_assert(std::is_same<top::sub::sub::first_type, short>::value, "wrong");
45
static_assert(std::is_same<top::sub::sub, Sub<container, short, long>>::value, "wrong");
46
47
static_assert(std::is_same<top::sub::sub::sub::first_type, long>::value, "wrong");
48
static_assert(std::is_same<top::sub::sub::sub, Sub<container, long>>::value, "wrong");
49
#endif
50
51
// sollte eher gar nicht gehen
52
using sinnfrei = top::sub::sub::sub::sub::sub::sub;

von Urlaubär (Gast)


Lesenswert?


von cppbert3 (Gast)


Lesenswert?

Urlaubär schrieb:
> Siehe auch:
> 
https://old.reddit.com/r/cpp_questions/comments/knttmz/c17_how_to_skip_first_type_of_parameter_pack_and/

Ich wollte Antwort die über reddit gekommen ist hier auch noch posten, 
du warst schneller :)

von Wilhelm M. (wimalopaan)


Lesenswert?

Das std::tuple brauchst Du gar nicht.

Ein Typ-Container ist einfach
1
template<typename... I>
2
struct list{};

Darauf aufbauend kann man sich Meta-Funktionen definieren, wie size<> 
oder etwa auch front<>:
1
#include <type_traits>
2
#include <cstddef>
3
4
template<typename... I>
5
struct list{};
6
7
namespace detail {
8
    template<typename> struct size_impl;
9
    template<typename... II>
10
    struct size_impl<list<II...>> {
11
        using type = std::integral_constant<size_t, sizeof...(II)>;
12
    };
13
14
    template<typename> struct front_impl;
15
16
    template<typename F, typename... II>
17
    struct front_impl<list<F, II...>> {
18
        using type = F;
19
    };
20
}
21
22
template<typename List>
23
using size = typename detail::size_impl<List>::type;
24
25
template<typename List>
26
inline static constexpr auto size_v = size<List>::value;
27
28
template<typename List>
29
using front = typename detail::front_impl<List>::type;

Damit geht dann:
1
using l1 = list<int, double>;
2
3
using f1 = front<l1>;
4
5
static_assert(std::is_same_v<f1, int>);

von Wilhelm M. (wimalopaan)


Lesenswert?

Man kann natürlich für die Meta-Programmierung auch Boost-Hana nehmen - 
je nach Geschmack. Seit constexpr-lambdas geht ja vieles einfacher.

von Wilhelm M. (wimalopaan)


Lesenswert?

BTW: es gibt ja keine syntaktisch vorgegebene Form von Meta-Funktionen 
in C++, aber für Funktionen F: type -> type hat sich seit Jahren obige 
Form eingebürgert.

Metafunktionen F: value -> value erledigt man heute eher mit constexpr / 
consteval Funktionen / closures.

Metafunktionen F: type -> value oder F: value -> type eher wieder nach 
obigem Muster.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.