2017-06-13 2 views
4

Variadische Vorlagen sind sehr nützlich für rekursive Operationen. In diesem Fall möchte ich, dass jeder rekursive Aufruf mit zwei Argumenten arbeitet, sodass ich nicht immer dieselbe Funktion aufrufen muss. Um dies zu erreichen kann ich schreiben:Gruppen von Argumenten in einer Variadic-Vorlage übergeben

f() {} 

template<typename M, 
     typename N, 
     typename... Rest> 
f(M arg1, N arg2, Rest... rest) 
{ 
    doStuff(arg1, arg2); 
    f(rest); 
} 

Dann würde ich diese als solche nennen:

f(arg1a, arg1b, 
    arg2a, arg2b, 
    arg3a, arg3b); 

jedoch, wenn der Anruf nicht so schön formatiert ist, und alle Argumente sind auf einer Linie, oder Die Spalte wird an der falschen Stelle geteilt, sie wird ziemlich unlesbar. Besonders wenn der Anruf ein Dutzend Paare enthält. Ich habe versucht, hier Abhilfe zu schaffen, indem ein Parameter Pack von Paaren erfordert in weitergegeben werden würde ich die Funktion gerne haben wie folgt aufgerufen werden:.

f({arg1a, arg1b}, 
    {arg2a, arg2b}, 
    {arg3a, arg3b}); 

Dies scheint vor allem zu sein Versagen als die Initialisiererliste nicht bekommt zu einem Paar abgeleitet. Ich kann make_pair für jeden Satz von Argumenten aufrufen, aber das löst nur ein Lesbarkeitsproblem mit einem anderen Lesbarkeitsproblem. Gibt es eine Möglichkeit, diese Art von Aufrufsyntax zum Laufen zu bringen? Die Argumente sind nicht über Paare oder Paare hinweg gleich.

+1

Können 'arg1a',' arg1b', 'arg2a',' arg2b', ... alle verschiedene Typen sein? – NathanOliver

+0

Ja. In meinem Fall sind sie alle Mitgliedsfunktionszeiger für Qt-Verbindungen, aber jede Funktion kann verschiedene Argumente annehmen. – TheLoneMilkMan

+2

OK. AFAIK die Sprache hat keine Möglichkeit, dies zu tun. '{arg1a, arg1b}' hat keinen Typ, daher können Sie keinen ableiten. – NathanOliver

Antwort

1

Es mag überraschend scheinen, aber die beste Lösung, die ich dafür gefunden habe, ist eigentlich eine "Explosion aus der Vergangenheit", die überhaupt keine Variadics verwendet.

struct F { 
    template <class M, class N> 
    F& operator()(M arg1, N arg2) { 
     doStuff(arg1, arg2); 
     return *this; 
    } 
}; 

F{} (arg1a, arg1b) 
    (arg2a, arg2b); 

Und so weiter. Obwohl, ich werde auch bemerken, dass Clang-Format dies nicht schön formatiert. Also habe ich wieder etwas anderes gemacht.

2

Entschuldigung, es ist nicht möglich: eine implizite Typumwandlung von der Klammerliste in einen benutzerdefinierten Typ. Und die einzige Konvertierung, die möglich ist, ist für std::initializer_list, aber es kann nur für die gleichen Typen oder für konvertierbare Typen erfolgen.

Mit diesem wird gesagt, ich würde das bieten, als eine Möglichkeit,

template <typename M, typename N> 
void doStuff(M&&, N&&) {} 

template <typename M, typename N> 
struct MyRepeater; 

template <typename M, typename N> 
MyRepeater<M, N> f(M&& one, N&& two); 

template <typename M, typename N> 
struct MyRepeater { 
    template <typename I, typename J> 
    MyRepeater<I, J> operator()(I&& one, J&& two) const { 
    return f(std::forward<I>(one), std::forward<J>(two)); 
    } 
}; 

template <typename M, typename N> 
MyRepeater<M, N> f(M&& one, N&& two) { 
    doStuff(one, two); 
    return MyRepeater<M, N>(); 
} 

int main() { 
    f(Foo1(), Foo2())(Bar1(), Bar2())(Bar2(), Foo1()); 
} 

Natürlich ist der Nachteil, dass nur für die Lesbarkeit ist, Sie haben zwei etwas mehr Code (meiner Meinung nach zu schreiben, ist es nicht ein schlechte Motivation).

Verwandte Themen