1

Возьмем следующую функцию-член:Forwarding, реф классификаторы и функции-члены шаблонов

struct T { 
    template <typename X> void f(X&& x) { /* ... */ } 
}; 

В этом случае x является ссылкой переадресации, поскольку && используется для параметров функции внутри шаблона. Это так, как ожидалось.

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

struct T { 
    template <typename X> void f(X&& x) && { /* ... */ } 
}; 

Я бы ожидать, что this будет рассматриваться таким же образом; в качестве справочника пересылки. Поэтому я ожидаю, что следующая программа для компиляции и запуска просто отлично:

#include <iostream> 

struct T { 
    template <typename X> 
    bool operator<(X&& rhs) && { 
     std::cout << "&&" << std::endl; 
     return true; 
    } 
}; 

int main() { 
    T t; 
    std::cout << (t < T()) << std::endl; 
    return 0; 
} 

Но с помощью GCC 4.8.4 и 6.0.1, это не так. Вместо этого, я получаю следующее:

rvalue.cpp: In function ‘int main()’: 
rvalue.cpp:13:25: error: passing ‘T’ as ‘this’ argument of ‘bool T::operator<(X&&) && [with X = T]’ discards qualifiers [-fpermissive] 
std::cout << (t < T()) << std::endl; 

Казалось бы, что this не сделал ссылку переадресации. Это правильно или ошибка? Должен ли this рассматриваться как ссылка для пересылки? В какой части стандарта это указано?

+0

@JoachimPileborg просто попробовал его с 6.0.1, тот же результат. Спасибо хоть! – OMGtechy

ответ

3

Два && s` здесь трактуется по-разному:

struct T { 
    template <typename X> void f(X&& x) && { /* ... */ } 
}; 

Вы правы в том, что x является ссылкой переадресации. Но && справа является квалификацией экземпляра объекта. В этом случае f() может быть вызван только в том случае, если экземпляр объекта является rvalue (возможно, добавление к путанице состоит в том, что первый && принимает x в качестве ссылки пересылки, а второй && принимает неявный объектный параметр в качестве ссылки на rvalue).То есть:

T().f(4); // ok 

T t; 
t.f(4); // error 

Это работает точно так же, как const квалификация делает:

struct X { void f(); }; 
const X cx; 
cx.f(); // error 
+0

Итак, шаблон не влияет на то, как '&&' применяется к 'this'? – OMGtechy

+1

@OMGtechy Это совершенно разные понятия. Вы не можете настроить квалификацию функции - если вы хотите перегружать lvalue и rvalue, вам нужно иметь функции '&' - и '&&' -qualified отдельно. – Barry

+0

Спасибо. Есть ли место в стандарте, где указано это различие? – OMGtechy

2

Ссылочный определитель в конце функции указывает, что operator< следует вызывать только при временном LHS. Помните оператор может называться как и любой другой функции члена, так что у вас есть

t.operator<(T()) 

t и не является временным.

Если мы изменим свой пример

std::cout << (T() < t) << std::endl; 

Тогда она работает просто отлично, как объект, который вы вызываете operator< на временный объект.

+0

Я понимаю это, я спрашиваю, почему 'this' не делает ссылку пересылки, как аргумент. – OMGtechy

+0

@OMGtechy Потому что компилятор не собирается конвертировать ваш объект в rvalue. Если бы это было так, ссылка на квалификацию была бы бесполезной. Вы сказали, что функция должна вызываться только на rvalue. Когда вы нарушаете это и вызываете его на объекте, который является значением lvalue, вы получаете ошибку компилятора. – NathanOliver

+0

@OMGtechy: Прежде всего, существует разница между * forwarding-reference * и * rvalue-reference *. Во-вторых, внутри функции-члена 'this' ** не является ** ссылочной ссылкой, ** или ** ссылкой на rvalue, даже внутри функций, которые могут быть вызваны только на rvalue, и в этом случае' this', хотя все еще сам lvalue, привязывается к выражению * rvalue *. – Nawaz

0

Член operator<() && можно назвать на RValue только, так следующее:

t < T() 

не будет работать, потому что t не rvaluelvalue.

должно работать:

std::move(t) < T() 

и это тоже:

T{} < T{} 

Обратите внимание, что я использовал {}, как я более комфортно с ними, и они работают без особого удивления.

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

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