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): примечание: шаблон кандидат игнорируется: сбой подстановки [с T => std::vector<int, std::allocator<int> > &]: тип 'std::vector<int, std::allocator<int> > &' не могут быть использованы до '::', потому что он имеет нет членовПочему в этом случае не пересылается эталонная работа?

void f3(T&&)

Мой компилятор лязг 4,0.

К моему удивлению, f3(coll) терпит неудачу, а f1(coll) и f2(coll) оба в порядке.

Почему ссылка на пересылку не работает в этом случае?

+0

Сообщите нам об ошибке. – user2079303

+0

@ user2079303, см. Мое обновление. – xmllmx

+2

Что неясно о сообщении об ошибке? –

ответ

21

Поскольку T выводится в качестве ссылочного типа, вам нужно использовать std::remove_reference

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

Полный пример:

#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


Как правило, при использовании Ссылки на пересылку, type modification utilities очень удобно; прежде всего потому, что ссылки на пересылку сохраняет как value category, так и cv qualifications.

Пример 1:

  • Код ниже fails для компиляции, потому что T выводится, как std::vector<int>& и вы не можете иметь неконстантную ссылка связываются с временным в 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); 
    } 
    
  • Вы можете удалить ссылку, чтобы ее получить до 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); 
    } 
    

Пример 2 (основывается на примере 1):

  • Простое удаление ссылки будет not work в коде ниже, потому что выведенная тип несет const квалификацию, (он же, T выводится в const std::vector<int>&) нового типа, RemoveReferenceT является 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); 
    } 
    
  • We can удалите квалификаторы cv с удаленной ссылкой.

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

Мы можем пойти дальше и дальше, причины, мы можем combine их в одну линию, вкладывая их, как: ==>using D = std::remove_cv_t<std::remove_reference_t<T>>.

Хотя есть std::decay, что это действительно мощный и short для такого «комбо-удар» (но иногда вы хотите a little less что std::decay делает).

 Смежные вопросы

  • Нет связанных вопросов^_^