2017-02-23 56 views
17
#include <vector> 

using namespace std; 

template<typename T, typename = decltype(&T::size)> 
void f1(T) 
{} 

template<typename T, typename = decltype(&T::size)> 
void f2(T&) 
{} 

template<typename T, typename = decltype(&T::size)> 
void f3(T&&) 
{} 

int main() 
{ 
    vector<int> coll; 

    f1(coll); // ok 
    f2(coll); // ok 
    f3(coll); // error : no matching function for call to 'f3' 
} 

main.cpp (21,6) Uwaga: szablon kandydat ignorowane: brak substytucji [Z T => std::vector<int, std::allocator<int> > &] Typ „std::vector<int, std::allocator<int> > &” nie może być stosowany przed „::”, ponieważ zawiera Brak użytkownikówDlaczego nie przekazuje pracy referencyjnej w tym przypadku?

void f3(T&&)

Moje kompilator jest dzyń 4.0.

Ku mojemu zaskoczeniu, f3(coll) kończy się niepowodzeniem, podczas gdy f1(coll) i f2(coll) są w porządku.

Dlaczego odwołanie do przekazywania nie działa w takim przypadku?

+0

Pokaż nam również uwagę na temat błędu. – user2079303

+0

@ user2079303, zobacz moją aktualizację. – xmllmx

+2

Co jest niejasne w przypadku komunikatu o błędzie? –

Odpowiedz

21

Ponieważ T jest wyprowadzany jako rodzaj odniesienia, trzeba użyć std::remove_reference

template<typename T, typename = decltype(&std::remove_reference_t<T>::size)> 
void f3(T&&) 
{} 

Pełny przykład:

#include <vector> 
#include <type_traits> 

using namespace std; 

template<typename T, typename = decltype(&T::size)> 
void f1(T) 
{} 

template<typename T, typename = decltype(&T::size)> 
void f2(T&) 
{} 

template<typename T, typename = decltype(&std::remove_reference_t<T>::size)> 
void f3(T&&) 
{} 

int main() 
{ 
    vector<int> coll; 

    f1(coll); // ok 
    f2(coll); // ok 
    f3(coll); // ok 
} 

Demo


Generalnie podczas korzystania Spedycja Referencje, type modification utilities jest bardzo przydatny; głównie dlatego, że przesyłające odniesienia zachowują zarówno value category i cv qualifications.

Przykład 1:

  • Kod poniżej fails kompilacji ponieważ T jest wyprowadzany jako std::vector<int>& i nie może mieć const odniesienia wiązania do tymczasowego w foo:

    #include <vector> 
    
    template<typename T> 
    void foo(T&&){ 
        T nV = {3, 5, 6}; 
    } 
    
    int main(){ 
        std::vector<int> Vec{1, 2 ,3, 4}; 
        foo(Vec); 
    } 
    
  • Możesz usunąć odwołanie, aby uzyskać numer work:

    #include <vector> 
    
    template<typename T> 
    void foo(T&&){ 
        using RemovedReferenceT = std::remove_reference_t<T>; 
        RemovedReferenceT nV = {3, 5, 6}; 
    } 
    
    int main(){ 
        std::vector<int> Vec{1, 2 ,3, 4}; 
        foo(Vec); 
    } 
    

Przykład 2 (opiera się przykład 1)

  • jedynie usunięcie odniesienia będzie not work w poniższej kodu ponieważ wyprowadzoną typu przenosi const kwalifikacje (aka T wyprowadza jak const std::vector<int>&) nowego typu, RemoveReferenceT jest const std::vector<int>:

    #include <vector> 
    
    template<typename T> 
    void foo(T&&){ 
        using RemovedReferenceT = std::remove_reference_t<T>; 
        RemovedReferenceT nV = {3, 5, 6}; 
        nV[2] = 7;        //woopsie 
    } 
    
    int main(){ 
        const std::vector<int> Vec{1, 2 ,3, 4}; //note the const 
        foo(Vec); 
    } 
    
  • Mamy can usuń kwalifikatory cv z typu usuniętego odniesienia.

    #include <vector> 
    
    template<typename T> 
    void foo(T&&){ 
        using RRT = std::remove_reference_t<T>; 
        using Removed_CV_of_RRT = std::remove_cv_t<RRT>; 
    
        Removed_CV_of_RRT nV = {3, 5, 6}; 
        nV[2] = 7; 
    } 
    
    int main(){ 
        const std::vector<int> Vec{1, 2 ,3, 4}; 
        foo(Vec); 
    } 
    

Możemy iść dalej i dalej, przyczyny, możemy combine je w jednej linii przez ich gniazdowania, jak: ==>using D = std::remove_cv_t<std::remove_reference_t<T>>.

Choć istnieje std::decay że jest naprawdę mocny i short dla takiego „kick combo” (ale czasami chcesz a little less co std::decay robi).