2015-08-28 15 views
5

mogę stworzyć zmiennej liczbie argumentów szablonu który akceptuje jedynie wskaźniki:Tworzenie zmiennej liczbie argumentów akceptując jedynie odniesienie lub wskaźnik

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

lub zmiennej liczbie argumentów szablonu który akceptuje tylko nazwy:

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

Jak mogę utworzyć szablon który akceptuje referencję lub wskaźnik?
E.g.

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

Uwaga: wersja referencyjna może wydawać się w porządku, ponieważ może to wiązać się z odniesieniami wskaźnik, ale nie jest, ponieważ nie będą wiązać się z int * const

+1

myślę, że należy przyjąć ogólne '' Rodzaje ... a następnie sprawdzić ich wskaźników jest lub odwołanie przez coś podobnego 'std :: is_pointer' –

+0

@PaoloM: Pierwszy przykład nie zadziała wtedy. – Dani

Odpowiedz

6

Możemy napisać cechę, by sprawdzić, czy typ jest wskaźnikiem lub non-const odniesienia:

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)>; 

Wtedy możemy napisać cechę to sprawdzić na opakowaniu parametru za pomocą Jonathan Wakely's and_:

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>...>; 

teraz możemy użyć std::enable_if aby potwierdzić typ:

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

Należy zauważyć, że odwołanie do przekazywania jest konieczne do wykrycia kategorii wartości argumentu, aby sprawdzić odwołanie działa poprawnie.

Live Demo

+0

Przez * przekazywanie odniesienia * masz na myśli * wzorzec uniwersalny * tzn. "Typy &&"? –

+1

@PaoloM tak, ale uważam, że "odniesienie do przekazywania" jest teraz [preferowanym terminem] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf). – TartanLlama

+0

Jeśli Bjarne mówi tak ... Dzięki;) –

1

można po prostu sprawdzić wymagania dla każdego typu w Args - przykład wygląda następująco:

// 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>>{}...>{}> 
{} 

Zakładając, że F służy wyłącznie z odliczenia wyłącznie lwartościami i wskaźniki będą dozwolone. Demo ze swoim przykładem.

+0

Myślę, że należy sprawdzić, czy wskazany typ jest oznaczony "const", ponieważ pozwoli to na wywołanie z 'const int a; F (a); ' – TartanLlama

+0

@TartanLlama Myślę, że jego intencją było, aby nie dopuszczać wartości r. – Columbo

+0

ah, prawdopodobnie masz rację. Łatwo jest odpowiedzieć, jeśli OP i tak chce to zrobić. – TartanLlama

Powiązane problemy