Всем привет,
Перечитал и пересмотрел кучу материала по теме RValue references
Тема вроде уже заезжанная, но вот не могу уложить себе один момент в голове.
| Скрытый текст |
| // TEMPLATE FUNCTION forward
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg) // Зачем реализовано именно так?
{ // forward an lvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT // Зачем реализовано именно так?
{ // forward anything
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
// Здесь со специализациями шаблона, понятно как это работает. Но вот непонятно почему это реализовано именно так?
// TEMPLATE remove_reference
template<class _Ty>
struct remove_reference
{ // remove reference
typedef _Ty type;
};
template<class _Ty>
struct remove_reference<_Ty&>
{ // remove reference
typedef _Ty type;
};
template<class _Ty>
struct remove_reference<_Ty&&>
{ // remove rvalue reference
typedef _Ty type;
};
|
| |
Казалось бы, почему бы не сделать так:
| Скрытый текст |
| // TEMPLATE FUNCTION forward
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type _Ty& _Arg) // Почему не так?
{ // forward an lvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type _Ty&& _Arg) _NOEXCEPT // Почему не так?
{ // forward anything
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
|
| |
А дальше начинается самое интересное.
При таком коде компилятор (от VS 2012 и g++ 4.8.2)
| Скрытый текст |
| ПРИМЕР1 :
template<typename T>
void Test(T&) {}
template<typename T>
void Test(T&&) {}
int main()
{
X x1;
Test(x1);
}
Это от MS compiler
error C2668: 'Test' : ambiguous call to overloaded function
1> f:\projects\c++\stl_tests\main.cpp(94): could be 'void Test<X&>(T)'
1> with
1> [
1> T=X &
1> ]
1> f:\projects\c++\stl_tests\main.cpp(91): or 'void Test<X>(T &)'
1> with
1> [
1> T=X
1> ]
1> while trying to match the argument list '(X)'
|
| |
Да, я знаком с "reference collapsing rules". Т.е почему так происходит я понимаю, но я не совсем понимаю, почему не выбирается явная реализация:
| Скрытый текст |
| template<typename T>
void Test(T&) {}
|
| |
Почему так должно быть? Ну например, при перегрузке функций с явными типами все работает логично ( т.е выбирвается TestInt(int&) , т.к параметр x1 lvalue ) :
| Скрытый текст |
| void TestInt(int &) {}
void TestInt(int &&) {}
int main()
{
int x1;
TestInt(x1);
}
|
| |
Небольшой поиск наталкивает:
На следующую тему:
Overload ambiguity when passing R-value to function that takes L-value
Оттуда есть ссылка сюда: 1164.
Partial ordering of f(T&) and f(T&&)
В драфтовой версии С++ (n3793) в 14.8.2.4/9 Изменения внесли.
А, вот теперь вопросы:
1. Поведение компилятовов на код из "ПРИМЕР1", получается не соответствуют стандарту?
2. Именно по этому приходится извращаться с
typename remove_reference<_Ty>::type
в параметрах?