typunabhängige variadische Funktionsvorlagen in C++11

Lesezeit: 7 Minuten

Ich sah ein Blogeintrag die typunabhängige variadische Vorlagen verwendet (derzeit nicht von gcc unterstützt, nur von clang).

template <class T, size_t... Dimensions>
struct MultiDimArray { /* ... */ };

Das Beispiel im Beitrag lässt sich gut kompilieren, aber ich habe es nicht geschafft, es mit Funktionsvorlagen zum Laufen zu bringen.

Kann jemand helfen, die korrekte Syntax herauszufinden (falls vorhanden)?

int max(int n) { return n; } // end condition

template <int... N> // replacing int... with typename... works
int max(int n, N... rest) // !! error: unknown type name 'N'
{
    int tmp = max(rest...);
    return n < tmp? tmp : n;
}

#include <iostream>
int main() 
{
   std::cout << max(3, 1, 4, 2, 5, 0) << std::endl;   
}

  • Ich dachte ein Variadic max existiert bereits in der Standardbibliothek… aber ich bin mir nicht ganz sicher.

    – Kerrek SB

    24. Okt ’11 um 15:03


  • @Kerrek max ist nicht der Punkt, es ist nur ein Beispiel.

    – Motti

    24. Okt. ’11 um 15:20

  • Möchtest du ein Nicht-Kompilierungszeit Funktion (dh max(3,1,4,foo(),5,bar()) im Gegensatz zu max<3,1,4,2,5,6>()), die eine beliebige Anzahl von Parametern benötigt, alle vom gleichen Typ? Und was bringt das Maximum?

    – Aaron McDaid

    1. Februar ’12 um 1:35


  • @AaronMcDaid, ja, ich habe nach einer Funktion ohne Kompilierzeit gesucht. Dank der Erklärungen von Konrad & Luc habe ich seitdem die Fehler meines Weges gesehen.

    – Motti

    1. Februar ’12 um 7:13

  • Warten Sie, warum sagen Sie, dass gcc dies nicht unterstützt? Kompiliert gut mit 4.9

    – RamblingMad

    10. Juli ’15 um 22:54

typunabhangige variadische Funktionsvorlagen in C11
Konrad Rudolph

Sie verwechseln einfach Typnamen und Nichttypnamen. Was Sie wollen, funktioniert einfach nicht.

Sie kann Verwenden Sie wahrscheinlich variadische Nicht-Typ-Vorlagen in Funktionen, aber nicht als (Nicht-Vorlagen-)Argumente:

template <int N, int... Rest>
int max()
{
    int tmp = max<Rest...>();
    return N < tmp ? tmp : N;
}
std::cout << max<3, 1, 4, 2, 5, 0>() << std::endl;

… obwohl ich das nicht getestet habe und mir nicht sicher bin wie Dies sollte funktionieren, da Sie als Basisfall eine Teilspezialisierung benötigen. Sie könnten dies lösen, indem Sie an eine teilweise spezialisierte Struktur senden:

template <int N, int... Rest>
struct max_t {
    static int const value = max_t<Rest...>::value > N ? max_t<Rest...>::value : N;
};

template <int N>
struct max_t<N> {
    static int const value = N;
};


template <int... NS>
int max()
{
    return max_t<NS...>::value;
}

Das wird funktionieren.

  • Ich suche keine Kompilierzeitfunktion. Durch die Nutzung typename... N wir erhalten das gleiche Verhalten, da die Parameter schließlich gezwungen werden zu int (der erste Parameter für jede Überladung von max ist int) aber es ist (IMO) etwas weniger elegant, das möchte ich konkretisieren diese Funktion nimmt eine beliebige Anzahl eines bestimmten Typs an. Eins könnten benutzen initializer_list aber dann müsste die Anrufseite geschweifte Klammern verwenden.

    – Motti

    24. Okt. 11 um 15:29 Uhr


  • @Motti Wie mein erster Absatz sagt, funktioniert das, was Sie wollen, einfach nicht.

    – Konrad Rudolph

    24. Okt. 11. um 16:36 Uhr

  • @Motti template<int I> void foo(I i); wäre unsinnig. Sie müssen das verstehen, bevor Sie variadisch werden.

    – Luc Danton

    24. Okt. ’11 um 16:44 Uhr

  • @Motti: Wenn Sie nicht nach einer Kompilierzeitfunktion suchen, suchen Sie auch nicht nach Vorlagenparametern, die nicht vom Typ sind. Nicht-Typ-Vorlagenparameter müssen konstante Ausdrücke zur Kompilierzeit sein.

    – Ben Voigt

    24. Okt. 11 um 16:56 Uhr

  • @LucDanton Wenn Sie es so ausdrücken, ist es offensichtlich, dass variadische Vorlagen meine Intuition durcheinanderbringen. Anscheinend grok ich sie noch nicht.

    – Motti

    24. Okt. 11 um 18:36 Uhr

typunabhangige variadische Funktionsvorlagen in C11
parker0203

Dadurch werden alle Elemente ausgedruckt, get max könnte ähnlich implementiert werden

template <int N>
void foo(){
  cout << N << endl;
}

template <int N, int M, int ... Rest>
void foo(){
  cout << N << endl;
  foo<M, Rest...>();
}


int main(){
  foo<1, 5, 7>();

  return 0;
}

  • Ich mag die Art und Weise, wie Sie die Mehrdeutigkeit vermeiden.

    – Bausatz Fisto

    25. Juli ’13 um 16:03

  • @parker0203 Warum benötigt die primäre Vorlage drei Vorlagenargumente? ich dachte template <int N, int ... Rest>foo(){ foo<Rest...>(); } würde genügen.

    – Olumid

    29. November ’16 um 13:12

  • Es reicht nicht, deshalb sind die M, N, Rest… alle notwendig, MSVC 2017 spuckt Fehler aus, wenn sie mit foo<1,2>() aufgerufen werden; error C2668: ‘foo’: Mehrdeutiger Aufruf einer überladenen Funktion könnte ‘void foo<2,>(void)’ oder ‘void foo<2>(void)’ sein.

    – zhaorufei

    8. September ’21 um 9:25

Hier sind zwei Möglichkeiten, eine variadische Funktionsvorlage zu definieren, die nur akzeptiert int Parameter. Der erste erzeugt bei der Instanziierung einen harten Fehler, der zweite verwendet SFINAE:

template<typename... T>
struct and_: std::true_type {};

template<typename First, typename... Rest>
struct and_
: std::integral_constant<
    bool
    , First::value && and_<Rest...>::value
> {};

template<typename... T>
void
foo(T... t)
{
    static_assert(
        and_<std::is_same<T, int>...>::value
        , "Invalid parameter was passed" );
    // ...
}

template<
    typename... T
    , typename = typename std::enable_if<
        and_<std::is_same<T, int>...>::value
    >::type
>
void
foo(T... t)
{
    // ...
}

Wie Sie sehen, werden hier keine typfremden Vorlagenparameter verwendet.

  • sehr interessante Verwendung von Vorlagen. kann auch wenige Anwendungen haben. 🙂

    – KaffeeEntwickler

    28. Juni ’13 um 1:23

  • Gute Idee, aber das funktioniert in keiner GCC-Version. > Fehler: mit 2 Vorlagenparametern neu deklariert > > Hinweis: vorherige Deklaration ‘template struct and_’ used 1 . godbolt.org/g/cQDSA0

    – Benutzer877329

    29. Dezember ’16 um 14:11


1641736155 466 typunabhangige variadische Funktionsvorlagen in C11
Richard Smith

Die Lösung von Luc Danton verhält sich nicht korrekt mit Parametern, die nicht vom Typ sind int, kann aber implizit in an . umgewandelt werden int. Hier ist eine, die tut:

template<typename T, typename U> struct first_type { typedef T type; };
template<typename T> int max_checked(T n) { return n; }
template<typename T1, typename T2, typename ...Ts>
int max_checked(T1 n1, T2 n2, Ts ...ns)
{
  int maxRest = max_checked(n2, ns...);
  return n1 > maxRest ? n1 : maxRest;
}
template<typename ...T> auto max(T &&...t) ->
  decltype(max_checked<typename first_type<int, T>::type...>(t...))
{
  return max_checked<typename first_type<int, T>::type...>(t...);
}

struct S { operator int() { return 3; } };
int v = max(1, 2.0, S()); // v = 3.

Hier, max leitet alle Argumente unverändert an . weiter max_checked, das die gleiche Anzahl von Argumenten vom Typ . akzeptiert int (bereitgestellt durch Durchführen einer Pack-Erweiterung auf dem first_type Schablone). Der decltype(...) Rückgabetyp wird verwendet, um SFINAE anzuwenden, wenn ein Argument nicht konvertiert werden kann in int.

So erreichen Sie variadische Argumente in Ihrem max Beispiel so, dass es eine beliebige Anzahl von arithmetischen Argumenten annehmen kann:

template<typename T, typename ... Ts>
struct are_arithmetic{
    enum {
        value = std::is_arithmetic<T>::value && are_arithmetic<Ts...>::value
    };
};

template<typename T>
struct are_arithmetic<T>{
    enum {
        value = std::is_arithmetic<T>::value
    };
};

template<typename Arg, typename = typename std::enable_if<std::is_arithmetic<Arg>::value>::type>
Arg max(Arg arg){
    return arg;
}

template<typename Arg, typename Arg1, typename ... Args, typename = typename std::enable_if<are_arithmetic<Arg, Arg1, Args...>::value>::type>
auto max(Arg arg, Arg1 arg1, Args ... args){
    auto max_rest = max(arg1, args...);
    return arg > max_rest ? arg : max_rest;
}

int main(){
    auto res = max(1.0, 2, 3.0f, 5, 7l);
}

Dies ist gut, da es jeden numerischen Typ annehmen kann und die maximale Zahl nach ihrem ursprünglichen Typ zurückgibt, anstatt nur int, auch.

  • Wenn ich das laufe, ist die Art von res ist double nicht long. Wie auch immer, ich habe versucht, Nicht-Typ-Vorlagenparameter zu verstehen. Ihre Lösung ist zwar cool, aber nicht das, wonach ich gesucht habe. Danke trotzdem. ideone.com/gUnoLp

    – Motti

    12. Juli ’15 um 10:36


  • Wenn ich das laufe, ist die Art von res ist double nicht long. Wie auch immer, ich habe versucht, Nicht-Typ-Vorlagenparameter zu verstehen. Ihre Lösung ist zwar cool, aber nicht das, wonach ich gesucht habe. Danke trotzdem. ideone.com/gUnoLp

    – Motti

    12. Juli ’15 um 10:36


.

215030cookie-checktypunabhängige variadische Funktionsvorlagen in C++11

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy