#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]
然而,根据is_rvalue_ref_func
对于两个类模板部分特化,第一个是至少 如第二个if那样专门,给出以下重写为2 功能模板,第一个功能模板至少为 根据功能的排序规则专门作为第二个 模板(14.5.6.2):
- 第一个功能模板具有相同的功能 模板参数作为第一个局部特化并具有 单个函数参数,其类型是类模板 使用第一个部分的模板参数进行特化 专业化,
- 第二个功能模板具有相同的功能 模板参数作为第二部分特化并具有 单个函数参数,其类型是类模板 使用第二个部分的模板参数进行专门化 专业化。
在上面的示例中,is_rvalue_ref
重载是通过精确执行{{1}}主模板和部分特化的重写来获得的。为什么函数调用不明确但类模板匹配定义良好?
答案 0 :(得分:3)
如果匹配,则部分特化将自动优先于主要特化。 [temp.class.spec.match] / 1:
在需要的上下文中使用类模板时 实例化该类,有必要确定是否 实例化将使用主模板或其中一个生成 部分专业化。这是通过匹配模板来完成的 使用模板的类模板特化的参数 部分专业化的参数列表。
(1.1) - 如果找到一个匹配的特化,那么 实例化是从该专业化生成的。
对于函数调用,虽然部分排序开始 - 并且为了参数推断而忽略了引用,[temp.deduct.partial] / 5:
在部分排序完成之前,某些转换是 对用于部分排序的类型执行:
(5.1) - 如果
P
是引用类型,则P
将替换为类型 提到。
...这使得函数模板等效于部分排序。因此呼叫含糊不清。
答案 1 :(得分:1)
在上面的例子中,
is_rvalue_ref_func
重载是通过获得的 正确执行is_rvalue_ref
主要的重写 模板和部分专业化。
几乎没有。
第一个函数模板具有与之相同的模板参数 第一部分特化并具有单个函数参数 type是具有模板参数的类模板特化 第一个部分专业化
给定类模板template<class> class SomeTemplate;
,正确的重写是
template<class T> void is_rvalue_ref_func(SomeTemplate<T>);
template<class T> void is_rvalue_ref_func(SomeTemplate<T&&>);
答案 2 :(得分:0)
功能模板不是部分专用的。您的引用仅适用于部分类模板专业化。它使用函数重载决策的规则来定义哪种特化更专业化。
相反,函数模板被重载,并且有两个同样好的重载。注意,你不能部分专门化功能模板,你只能完全专门化它们。
如果你想使用一个函数模板来确定某个东西是否是一个rvalue你可以做这样的事情(我想;目前我不能轻易地测试代码):
template <typename T>
constexpr bool is_rvalue_func(T&&) {
return !std::is_reference<T>::value;
}
我认为你不能区分传递给函数的rvalues和rvalue引用。也就是说,我认为这两个都会产生true
,尽管只有后者实际上是对象的右值引用:
is_rvalue_func(int());
int i(17);
is_rvalue_func(std:move(i));