2015-08-28 7 views
5

ich eine variadische Vorlage erstellen können, die nur Zeiger akzeptiert:Erstellen variadische nur Referenz oder Zeiger zu akzeptieren

template<typename ... Types> 
void F(Types *... args); 

Oder eine variadische Vorlage, die nur Verweise akzeptiert:

template<typename ... Types> 
void F(Types &... args); 

Wie ich eine Vorlage erstellen das akzeptiert entweder nicht-const Referenz oder Zeiger?
Zum Beispiel

int a, b, c; 
F(a, &b); // => F<int &, int *> 
F(a, 3); // Error, 3 not pointer and cannot bind to non const-reference 

Hinweis: Die Referenzversion könnte ok erscheinen, weil es zu Zeiger Referenzen binden kann, aber es ist nicht, da es in Args für jeden Typ die Anforderungen überprüfen binden nicht einfach zu int * const

+1

Ich denke, Sie generische Typen 'annehmen sollten ...' und dann prüfen, ihr Sein Zeiger oder Referenz durch so etwas wie 'std :: is_pointer' –

+0

@PaoloM: Das erste Beispiel dann nicht funktionieren wird. – Dani

Antwort

6

Wir haben eine Eigenschaft schreiben zu überprüfen, ob ein Typ ein Zeiger oder eine nicht konstante Referenz ist:

template <typename T> 
using is_pointer_or_ref = 
    std::integral_constant<bool, std::is_pointer<T>::value || 
    (std::is_lvalue_reference<T>::value && 
    !std::is_const<typename std::remove_reference<T>::type>::value)>; 

Dann können wir ein Merkmal schreiben diese über einen Parameter Pack Jonathan Wakely's and_ mit überprüfen:

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

template<typename Cond, typename... Conds> 
    struct and_<Cond, Conds...> 
    : std::conditional<Cond::value, and_<Conds...>, std::false_type>::type 
    { }; 

template <typename... Ts> 
using are_pointer_or_ref = and_<is_pointer_or_ref<Ts>...>; 

Jetzt können wir std::enable_if verwenden, um die Art zu bestätigen:

template<typename ... Types, 
    typename std::enable_if<are_pointer_or_ref<Types...>::value>::type* = nullptr> 
void F(Types&&... args){} 

Beachten Sie, dass die Weiterleitungsreferenz erforderlich ist, um die Wertkategorie des Arguments zu erkennen, damit die Referenzprüfung ordnungsgemäß funktioniert.

Live Demo

+0

Durch * Weiterleitungsreferenz * meinst du * universelle Referenz * d. H. Die 'Typen &&'? –

+1

@PaoloM Ja, aber ich glaube, "Weiterleitungsreferenz" ist der [bevorzugte Begriff jetzt] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf). – TartanLlama

+0

Wenn Bjarne so sagt ... Danke;) –

1

Sie - zum Beispiel thusly:

// Helper templates 
template <bool...> struct bool_pack {}; 
template <bool b, bool... rest> 
struct all_of : std::is_same<bool_pack<b, rest...>, bool_pack<rest..., b>> {}; 

template <typename... Args> 
auto F(Args&&... args) 
    -> std::enable_if_t<all_of<std::is_lvalue_reference<Args>{} 
          or std::is_pointer<std::decay_t<Args>>{}...>{}> 
{} 

Unter der Annahme, dass F nur mit Abzug verwendet wird, ausschließlich lvalues ​​und Zeiger werden dürfen. Demo mit Ihrem Beispiel.

+0

Ich denke, Sie müssen überprüfen, ob der referenzierte Typ mit 'const' markiert ist, da dies das Aufrufen von 'const int a; F (a); ' – TartanLlama

+0

@TartanLlama Ich denke, seine Absicht war es, rvalues ​​nicht zuzulassen. – Columbo

+0

ah, du hast wahrscheinlich recht. Es ist eine einfache Lösung, ob OP beantwortet werden soll. – TartanLlama