2015-02-14 3 views
0
#include <iostream> 
#include <utility> 

template <class T> struct is_rvalue_ref  : std::false_type {}; 
template <class T> struct is_rvalue_ref<T&&> : std::true_type {}; 

template <typename T> bool is_rvalue_ref_func(T){return false;} 
template <typename T> bool is_rvalue_ref_func(T&&){return true;} 

class A {}; 

int main() 
{ 
    std::cout << std::boolalpha; 
    std::cout << is_rvalue_ref<A>::value << '\n'; 
    std::cout << is_rvalue_ref<A&>::value << '\n'; 
    std::cout << is_rvalue_ref<A&&>::value << '\n'; 

    /*****THIS FAILS TO COMPILE************ 
    A a; 
    A& alv = a; 
    A&& arv = std::move(a); 
    std::cout << is_rvalue_ref_func(a) << '\n'; 
    std::cout << is_rvalue_ref_func(alv) << '\n'; 
    std::cout << is_rvalue_ref_func(arv) << '\n'; 
    **************************************/ 

    return 0; 
} 

Компилятор (clang 3.5 -std=c++11) не имеют никаких проблем неоднозначности вызовы is_rvalue_ref пока он уклоняется от is_rvalue_ref_func перегрузок с:Почему следующий шаблон шаблона не является двусмысленным?

rv.cpp:31:16: error: call to 'is_rvalue_ref_func' is ambiguous 
    std::cout << is_rvalue_ref_func(a) << '\n'; 
       ^~~~~~~~~~~~~~~~~~ 
rv.cpp:8:6: note: candidate function [with T = A] 
bool is_rvalue_ref_func(T) 
    ^
rv.cpp:14:6: note: candidate function [with T = A &] 
bool is_rvalue_ref_func(T&&) 
    ^
rv.cpp:32:16: error: call to 'is_rvalue_ref_func' is ambiguous 
    std::cout << is_rvalue_ref_func(alv) << '\n'; 
       ^~~~~~~~~~~~~~~~~~ 
rv.cpp:8:6: note: candidate function [with T = A] 
bool is_rvalue_ref_func(T) 
    ^
rv.cpp:14:6: note: candidate function [with T = A &] 
bool is_rvalue_ref_func(T&&) 
    ^
rv.cpp:33:16: error: call to 'is_rvalue_ref_func' is ambiguous 
    std::cout << is_rvalue_ref_func(arv) << '\n'; 
       ^~~~~~~~~~~~~~~~~~ 
rv.cpp:8:6: note: candidate function [with T = A] 
bool is_rvalue_ref_func(T) 
    ^
rv.cpp:14:6: note: candidate function [with T = A &] 
bool is_rvalue_ref_func(T&&) 
    ^
3 errors generated. 

Однако, по словам 14.5.5.2 [temp.class.order]

Для два шаблона класса частичных специализация, первая по меньшей мере равна как специализированная, как вторая, если с учетом следующей перезаписи на две функции: function templ Атес, первый шаблон функции, по крайней мере специализирован как вторые в соответствии с правилами заказа для функции шаблонов (14.5.6.2): ​​

- первый шаблон функции имеет те же параметров шаблона в качестве первой частичной специализации и имеет параметр в одной функции, тип которого шаблон класса специализации с аргументами шаблона первой частичной специализации и

- второй шаблон функции имеет те же параметров шаблона как вторая частичную специализация и имеет параметр одиночной функции, тип которого является шаблоном класса специализация с аргументами шаблона второй частичной специализации .

В приведенном выше примере, is_rvalue_ref_func Перегрузки получаются путем выполнения именно это переписывание is_rvalue_ref первичного шаблона и частичной специализации. Почему вызов функции неоднозначен, но шаблон шаблона соответствует четко определенному?

+0

Шаблоны функций не являются частично специализированными. Вместо этого они перегружены, и есть две одинаково хорошие перегрузки. Обратите внимание: вы не можете частично специализировать шаблон функции, вы можете полностью их специализировать. –

+0

@ DietmarKühl Согласен. Исправлено неточное название. Шаблоны функций, показанные в примере, являются просто перегрузками. Однако они генерируются в соответствии с правилами сопоставления шаблонов классов, указанными в вопросе. – Pradhan

+3

текст, который вы цитировали, говорит о «специализациях классов». Это 1. полная специализация с использованием аргументов, предоставляемых шаблону класса, 2. они являются классами. Вы кодируете для шаблонов функций ни один из них. –

ответ

1

В приведенном выше примере, is_rvalue_ref_func Перегрузки получается путем выполнение именно этой переписать is_rvalue_ref основной шаблон и частичная специализация.

Вряд ли.

первый шаблон функция имеет те же параметры шаблона как первой частичную специализация и имеет один параметр функции которого типа шаблон класса специализация с аргументами шаблона первой частичной специализацией

правильный переписывают, учитывая шаблон класса template<class> class SomeTemplate;, является

template<class T> void is_rvalue_ref_func(SomeTemplate<T>); 
template<class T> void is_rvalue_ref_func(SomeTemplate<T&&>); 
3

Частичные специализации автоматически предпочтительнее, чем первичные, если они совпадают. [Temp.class.spec.match]/1:

Когда шаблон класса используются в контексте, который требует экземпляра класса, то необходимо, чтобы определить Инстанциации ли быть сгенерирована с использованием первичный шаблон или один из частичных специализаций. Это делается путем сопоставления аргументов шаблона шаблона с шаблоном списков аргументов частичных специализаций.

(1.1) - Если найдено только одна совпадающая специализация, то из этой специализации создается экземпляр .

Для вызова функции, частичное упорядочение пинками в, хотя - и он игнорирует ссылки для целей аргумента дедукции [temp.deduct.partial]/5:

Перед тем как частичное упорядочение делается , определенные преобразования выполняется на типы используемого для частичного упорядочения:

(5.1) - Если P является ссылочным типом, P заменяются типом ссылки.

... который делает шаблоны функций эквивалентными для частичного заказа. Таким образом, вызов неоднозначен.

+0

А, ок. Дальнейший вопрос: почему поведение сопоставления шаблонов классов отличается от поведения сопоставления «универсальной ссылки», которое вы видите с помощью «шаблона void func (T &&);)? Почему ссылка lvalue (' A & ') не совпадает с 'template struct is_rvalue_ref ' специализация с 'T' выводится как' A & ', как это было бы с функциями? – Pradhan

+0

@Pradhan Потому что существует принципиальное различие, концептуально, между выводом аргумента шаблона для частичных специализаций и шаблонов функций. трудно объяснить, но последний гораздо более «расслаблен». – Columbo

+0

Не могли бы вы указать мне на соответствующие разделы?Я согласен с тем, что поведение в моем фрагменте кода не противоречит интуиции. Но я не могу вывести его из стандарта :) – Pradhan

0

Шаблоны функций не являются частично специализированными. Ваша цитата применима только к специализации с частичным классом. Он использует правила для разрешения перегрузки функции, чтобы определить, какая специализация более специализирована.

Вместо этого функции templaes перегружены и есть две одинаково хорошие перегрузки. Обратите внимание: вы не можете частично специализировать шаблон функции, вы можете полностью их специализировать.

Если вы хотите использовать шаблон функции для определения, если что-то является Rvalue вы могли бы сделать что-то вроде этого (я думаю, в настоящее время я не могу легко проверить код):

template <typename T> 
constexpr bool is_rvalue_func(T&&) { 
    return !std::is_reference<T>::value; 
} 

Я DON» t думаю, что вы можете различать rvalues ​​и rvalue ссылки, передаваемые функции. То есть, я думаю, что оба из них даст true, хотя только последний на самом деле является ссылка Rvalue к объекту:

is_rvalue_func(int()); 
int i(17); 
is_rvalue_func(std:move(i));