为什么下面的class模板匹配没有歧义?
Why is the following class template matching not ambiguous?
#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]
For two class template partial specializations, the first is at least
as specialized as the second if, given the following rewrite to two
function templates, the first function template is at least as
specialized as the second according to the ordering rules for function
templates (14.5.6.2):
— the first function template has the same
template parameters as the first partial specialization and has a
single function parameter whose type is a class template
specialization with the template arguments of the first partial
specialization, and
— the second function template has the same
template parameters as the second partial specialization and has a
single function parameter whose type is a class template
specialization with the template arguments of the second partial
specialization.
在上面的示例中,is_rvalue_ref_func
重载是通过精确地执行 is_rvalue_ref
主模板和部分特化的重写获得的。为什么函数调用不明确,但 class 模板匹配定义明确?
如果匹配,部分专业化优先于主要专业化。 [temp.class.spec.match]/1:
When a class template is used in a context that requires an
instantiation of the class, it is necessary to determine whether the
instantiation is to be generated using the primary template or one of
the partial specializations. This is done by matching the template
arguments of the class template specialization with the template
argument lists of the partial specializations.
(1.1) — If exactly one matching specialization is found, the
instantiation is generated from that specialization.
对于函数调用,部分排序开始了 - 它忽略了参数推导目的的引用,[temp.deduct.partial]/5:
Before the partial ordering is done, certain transformations are
performed on the types used for partial ordering:
(5.1) — If P
is a reference type, P
is replaced by the type
referred to.
... 这使得函数模板等同于部分排序。因此调用是不明确的。
函数模板不是部分特化的。您的报价仅适用于部分 class 模板专业化。它使用函数重载决议的规则来定义哪个特化更特化。
相反,函数模板被重载并且有两个同样好的重载。请注意,您不能部分特化函数模板,只能完全特化它们。
如果您想使用函数模板来确定某项是否为右值,您可以这样做(我认为;目前我无法轻松测试代码):
template <typename T>
constexpr bool is_rvalue_func(T&&) {
return !std::is_reference<T>::value;
}
不过,我认为您无法区分传递给函数的右值和右值引用。也就是说,我认为这两者都会产生 true
尽管只有后者实际上是对对象的右值引用:
is_rvalue_func(int());
int i(17);
is_rvalue_func(std:move(i));
In the above example, the is_rvalue_ref_func
overloads are obtained by
performing precisely this rewrite of the is_rvalue_ref
primary
template and partial specialization.
几乎没有。
the first function template has the same template parameters as the
first partial specialization and has a single function parameter whose
type is a class template specialization with the template arguments of
the first partial specialization
给定 class 模板 template<class> class SomeTemplate;
的正确重写是
template<class T> void is_rvalue_ref_func(SomeTemplate<T>);
template<class T> void is_rvalue_ref_func(SomeTemplate<T&&>);
#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]
For two class template partial specializations, the first is at least as specialized as the second if, given the following rewrite to two function templates, the first function template is at least as specialized as the second according to the ordering rules for function templates (14.5.6.2):
— the first function template has the same template parameters as the first partial specialization and has a single function parameter whose type is a class template specialization with the template arguments of the first partial specialization, and
— the second function template has the same template parameters as the second partial specialization and has a single function parameter whose type is a class template specialization with the template arguments of the second partial specialization.
在上面的示例中,is_rvalue_ref_func
重载是通过精确地执行 is_rvalue_ref
主模板和部分特化的重写获得的。为什么函数调用不明确,但 class 模板匹配定义明确?
如果匹配,部分专业化优先于主要专业化。 [temp.class.spec.match]/1:
When a class template is used in a context that requires an instantiation of the class, it is necessary to determine whether the instantiation is to be generated using the primary template or one of the partial specializations. This is done by matching the template arguments of the class template specialization with the template argument lists of the partial specializations.
(1.1) — If exactly one matching specialization is found, the instantiation is generated from that specialization.
对于函数调用,部分排序开始了 - 它忽略了参数推导目的的引用,[temp.deduct.partial]/5:
Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:
(5.1) — If
P
is a reference type,P
is replaced by the type referred to.
... 这使得函数模板等同于部分排序。因此调用是不明确的。
函数模板不是部分特化的。您的报价仅适用于部分 class 模板专业化。它使用函数重载决议的规则来定义哪个特化更特化。
相反,函数模板被重载并且有两个同样好的重载。请注意,您不能部分特化函数模板,只能完全特化它们。
如果您想使用函数模板来确定某项是否为右值,您可以这样做(我认为;目前我无法轻松测试代码):
template <typename T>
constexpr bool is_rvalue_func(T&&) {
return !std::is_reference<T>::value;
}
不过,我认为您无法区分传递给函数的右值和右值引用。也就是说,我认为这两者都会产生 true
尽管只有后者实际上是对对象的右值引用:
is_rvalue_func(int());
int i(17);
is_rvalue_func(std:move(i));
In the above example, the
is_rvalue_ref_func
overloads are obtained by performing precisely this rewrite of theis_rvalue_ref
primary template and partial specialization.
几乎没有。
the first function template has the same template parameters as the first partial specialization and has a single function parameter whose type is a class template specialization with the template arguments of the first partial specialization
给定 class 模板 template<class> class SomeTemplate;
的正确重写是
template<class T> void is_rvalue_ref_func(SomeTemplate<T>);
template<class T> void is_rvalue_ref_func(SomeTemplate<T&&>);