2016-04-25 8 views
-2

Я прочитал this (невероятно хорошо написанный) статья о Справочник по отправке в C++ 11 от Scott Meyers.C++: путаница в отношении ссылки на пересылку

Теперь акцент на этой части статьи:

template <class... Args> 
void emplace_back(Args&&... args); // deduced parameter types ⇒ type deduction; 
...        // && ≡ universal references 

Таким образом, в отличие от других случаев, эллипсы не делают && ссылку RValue, но это все-таки универсальные ссылки.

Из того, что я понял, когда у нас есть универсальные ссылки, мы можем вызвать функцию, проходящую как RValue и lvalues ​​(! Вау, круто)

Теперь я реализовал эту функцию:

template <typename ReturnType, typename... Args> 
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) { ... 

Таким образом (используя ту же логику предыдущего примера), && означает пересылку ссылок.

Но если я пытаюсь сделать этот призыв:

typedef vector<double> vecD; 
vecD vec; 
mem.callFunction<vecD, vecD>(sortFunc, vec); 

Компилятор собирается жаловаться с You cannot bind an lvalue to an rvalue reference

Почему это происходит?

ВЕСЬ КОД:

#include <functional> 
#include <vector> 

using namespace std; 
struct MultiMemoizator { 
    template <typename ReturnType, typename... Args> 
    ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) { 

    } 
}; 

typedef vector<double> vecD; 

vecD sort_vec (vecD const& vec) { 
    return vec; 
} 

int main() 
{ 
    vecD vec; 
    std::function<vecD(vecD)> sortFunc(sort_vec); 
    MultiMemoizator mem; 
    mem.callFunction<vecD, vecD>(sortFunc, vec); 
} 
+5

* Универсальные * ссылки были ужасным термином с самого начала, и теперь он, наконец, заменен гораздо более подходящей * пересылкой * реферирования. – SergeyA

+2

Вы уверены, что 'Args' фактически * выведен * в вашем звонке? –

+1

Я бы хотел увидеть настоящий MCVE. Из фрагмента он должен работать нормально. – SergeyA

ответ

7

Так прежде всего, пожалуйста, используйте "ссылку переадресации" вместо "универсальной ссылки". Он лучше представляет, что это такое и каково его предназначение.

Первое, о чем нужно знать, заключается в том, что не каждый && является ссылкой на пересылку. Он также может быть ссылкой rvalue.

В простых терминах T&& является ссылкой переадресации, если и только если:

  • T является простой (простой, как показано ниже) типа (так, например, vector<int>&& или vector<T>&& является не ссылки переадресации).
  • и T выведено.

В вашем примере Args не выведено.Это потому, что вы явно указать шаблон функции аргумент Args при вызове его:

mem.callFunction<vecD, vecD>(sortFunc, vec); 
         ^~~~ 

Давайте работать с чем-то простым, чтобы лучше понять:

Установим сцену:

struct X {}; 

template <class T> 
auto foo(T&& p) {} 

В течение следующих 2 вызовов мы имеем ссылки на пересылку:

X x; 
foo(x); 

foo(X{}); 

В первом, T будет выведено в X& и свернув правила: X& && становится X&, поэтому мы имеем Lvalue ссылку. Как и следовало ожидать.

Во втором T будет выведен в X и разрушающихся правилах X && становится X&&, поэтому у нас есть ссылка RValue. не

Но когда вы называете это так:

foo<X>(x); 

T больше не выводится. Вы в основном говорите, пусть T будет X. Так что если T - X, то T && - X&&, и у вас есть ошибка: p, тип которого сейчас X&& не может связываться с lvalue.


Холт также добавил:

Also note that because of the declaration of sortFunc, this would not work even if you did not specify the function template arguments explicitely.

Я склонен согласиться с ним, но мне нужно было исследовать дальше, чтобы убедиться в этом.

+0

Также обратите внимание, что из-за объявления 'sortFunc' это не сработает, даже если вы не указали аргументы шаблона функции явно. – Holt

+0

Я думаю, что я понял ваш ответ, но мой следующий вопрос: есть способ сделать мой код «пересылкой референциальной» (и поэтому вывести тип «Args»)? – justHelloWorld

+0

@justHelloWorld на первый взгляд, я бы сказал нет (по крайней мере, не без каких-то неприятных уродливых хаков). Вам нужно указать 'Args' для' sortFunc'. Возможно, если вы сделаете «memFunc» последним параметром (не знаете, возможно ли это), чтобы сначала вывести 'Args', а затем изменил подпись' memFunc'. Но вы можете добавить 'remove_reference_t' в подпись параметров' memFuc'. Как я уже сказал, уродливые уродливые хаки. – bolov

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

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