2015-04-19 2 views
2

Мне сказали here, что различия между этими двумя сигнатурами не связаны с lvalue/rvalue.В чем разница между этими двумя сигнатурами функций?

#include <iostream> 

template <typename RET_TYPE, typename...ARGs> 
void takeFunction(RET_TYPE(*&& /*function*/)(ARGs...)) 
{ 
    std::cout << "RValue function" << std::endl; 
} 

template <typename RET_TYPE, typename...ARGs> 
void takeFunction(RET_TYPE(*& /*function*/)(ARGs...)) 
{ 
    std::cout << "LValue function" << std::endl; 
} 

void function() 
{ 
} 

int main() 
{ 
    void(*f)() = function; 
    takeFunction(&function); 
    takeFunction(f); 
    return 0; 
} 

Но если это не так, то в чем разница, на которой оно соответствует?

+0

Полагает, что первая является ссылкой на функцию, а вторая - ссылкой на указатель функции. – Galik

ответ

3

Существует разница между функцией и указателем для функции.

Функции разные, потому что они не являются объектами (в стандартном смысле слова). Нет такой функции, как function rvalues ​​(за пределами определенных странных случаев, связанных с нестационарными функциями-членами). Фактически, rvalue ссылается на функцию: lvalues ​​ ли или нет.

Указатели на функции, ну, указатели, которые являются объектами. У вас может быть указатель на указатель на тип функции или значение x для указателя на тип функции или lvalue указателя на тип функции. &function создает указатель prvalue для функции; в void (*f)() = function; преобразование функции в указатель применяется для преобразования функции lvalue function в указатель prvalue для функции, с которой инициализируется f.

Теперь рассмотрит этот набор перегрузок:

template <typename RET_TYPE, typename...ARGs> 
void takeFunctionRef(RET_TYPE(&& /*function*/)(ARGs...)) // #1 
{ 
    std::cout << "RValue function" << std::endl; 
} 

template <typename RET_TYPE, typename...ARGs> 
void takeFunctionRef(RET_TYPE(& /*function*/)(ARGs...)) // #2 
{ 
    std::cout << "LValue function" << std::endl; 
} 

takeFunctionRef(function); // calls #2 
takeFunctionRef(std::move(function)); // still calls #2! 

перегрузка # 2 выбран из специального тай-брейка в [over.ics.rank], пуля 3.1.4, что способствует связыванию Lvalue ссылки на функцию lvalue по привязке ссылки rvalue к функции lvalue. Но оба будут успешно связываться (т. Е. Если вы удалите # 2, вы увидите # 1, вызываемый в обоих случаях).

+0

Итак, если вы указали набор перегрузок, только один из них доступен, если оба существуют (# 2), но могут быть использованы, если объявлены без другого? Я понимаю, что это не очень двусмысленно, но, по крайней мере, не должно ли оно генерировать предупреждение о том, что его никогда не назовут? – Adrian

+0

@Adrian Да, но я подозреваю, что такая ситуация действительно не встречается в реальном коде почти достаточно часто, чтобы оправдать затраты на внедрение предупреждения. –

+1

«Нет такой функции, как функция rvalues». - Ну, если мы говорим строго в соответствии со стандартом, я думаю, что есть некоторые значения типа функции, но их использование настолько тщательно ограничено, что вы просто не можете столкнуться с ними на практике в контексте, где действительно важна их категория ценности , Рассматривая 'struct A {void f() {}}; A a; ', выражения' A :: f' и 'a.f' являются значениями типа функции в соответствии с [5.1.1p9] и [5.2.5p4.3.2] соответственно. – bogdan

1

RET_TYPE(*&& /*function*/)(ARGs...) - это ссылка rvalue на указатель функции.

RET_TYPE(*& /*function*/)(ARGs...) является ссылкой на указатель функции.

&function создает временную указатель функции rvalue. Таким образом, takeFunction(&function); переходит на RET_TYPE(*&& /*function*/)(ARGs...).

void(*f)() = function; определяет указатель функции lvalue. Таким образом, takeFunction(f); переходит на RET_TYPE(*& /*function*/)(ARGs...).

Помимо этой разницы lvalue/rvalue нет других отличий от этих двух функций.

+0

И если бы у меня была третья 'RET_TYPE (&/* function * /) (ARGs ...)', это была бы ссылка на функцию, которая является lvalue? – Adrian

+0

Правильно. Кроме того, я, похоже, помню, что все ссылки rvalue на функцию практически разрешены как ссылки lvalue. Другими словами, вы не можете иметь ссылку на функцию rvalue. Собираюсь найти стандартную ссылку на это. – Lingxi

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