Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么在ADL中超负荷优先于显式专业化_C++_Templates_C++11_Overloading_Argument Dependent Lookup - Fatal编程技术网

C++ 为什么在ADL中超负荷优先于显式专业化

C++ 为什么在ADL中超负荷优先于显式专业化,c++,templates,c++11,overloading,argument-dependent-lookup,C++,Templates,C++11,Overloading,Argument Dependent Lookup,以代码为例: #include <iostream> #include <algorithm> // std::swap C++98 #include <utility> // std::swap C++11 namespace A { template<typename T> struct Foo {}; template<typename T> void swap(Foo<T> &lhs, Foo<T&

以代码为例:

#include <iostream>
#include <algorithm> // std::swap C++98
#include <utility> // std::swap C++11

namespace A
{
template<typename T>
struct Foo {};

template<typename T>
void swap(Foo<T> &lhs, Foo<T> &rhs)
{
    std::cout << "A::swap<T>" << std::endl;
}

} /* end namespace A */

namespace std // we explicitly specialize std::swap here
{

template<> // explicit template specialization for std::swap<int>
void swap(A::Foo<int> &lhs, A::Foo<int> &rhs) 
noexcept 
(is_nothrow_move_constructible<A::Foo<int>>::value && is_nothrow_move_assignable<A::Foo<int>>::value)
{
    std::cout << "std::swap<int>" << std::endl;
} 

} /* end namespace std */

int main()
{
    using std::swap;
    A::Foo<int> a, b; 
    A::Foo<double> x, y;

    swap(a, b); // ADL, expected to call std::swap<Foo<int>>, but NO
    swap(x, y); // ADL, expected to call A::swap<T>, YES
}

有人能解释为什么会有这种行为吗

显式函数模板专门化永远不会更改调用哪个函数模板或重载,只有在调用模板时才更改模板的实现

过载解决忽略了专门化(与重载相反,它看起来很像部分不熟悉C++函数模板古怪的人)。

我可以想象为什么:混合重载和模板专门化选择规则会使规则更难遵循和正确

一般来说,专门化函数模板很少是个好主意:重载或分派到模板类通常更好


请注意,该语言在重载解析中谈到了“更专业化”:不要将其与“模板专门化”混淆:它们是不同的概念,不可调和地共享一个词。

函数模板显式专门化不参与重载解析。只考虑从主模板合成的函数声明。如果重载解析过程选择了一个这样的函数作为最佳可行函数,则将在适当的情况下使用相应主模板的显式专门化

在这种情况下,重载解析需要在从
swap
函数模板重载执行
foo&
合成的函数声明和从
std::swap
主模板执行
T&
合成的函数声明之间进行选择


这两个函数中的任何一个都不能基于转换(它们具有相同的函数参数)进行选择,它们都是模板专用化,因此需要考虑函数模板的偏序,从而使您的
交换
函数模板更加专用,因此,从您的
交换
重载中合成的函数声明获胜。

如其他答案中所述,原因是 显式函数专门化不参与重载 决议

显式专门化的一个简单经验法则是,当使用特定模板参数调用主模板时,它们会更改将使用的定义

template <typename T> void foo (T) {
  // definition used for 'foo' when T is not 'int'
}

template <> void foo<int> (int) {
  // definition used for 'foo' when T is 'int'
}
为两种
交换生成主模板的专门化:

13.3.1p7:在每种情况下,候选人都是功能模板, 候选函数模板专门化是使用 模板参数推导(14.8.3、14.8.2)。这些候选人是 然后以通常的方式作为候选函数进行处理

NB:明确的专门化不是其中的一部分

对于
swap(a,b)
重载解析使用的候选集将 包含以下生成的函数模板专门化:

A::swap(Foo<int>&, Foo<int>)&);
std::swap(Foo<int>&, Foo<int>)&);

作为我日常工作的一部分,我们为“现代C++”制定了一套规则,这实际上是其中一条规则(14.2.2)。对于那些感兴趣的人,我的个人资料网站链接到可以在线免费浏览的规则。Herb Sutter的这篇优秀文章可能会让你感兴趣:我同意专业化这个术语在这里很混乱。我认为如果使用“从主模板合成”的函数声明或显式专门化的声明(显式规范的声明不能与主模板不同),那么这是不相关的。正如您在第三段中所说,重载集中两个函数的参数类型是相同的;在这一点上,它们是由不同的模式形成的并不重要(
foo&
vs
t&
)。关键:最终的偏序依赖于主模板,而不是显式的专门化。@dyp我明白你的意思-一个有趣的思路,我认为它同样正确。我想,如果在流程描述中提到明确的专业化,那么标准没有遵循这条路径来避免“人们获得任何想法”的可能性。在考虑这些事情时,我通常会尽可能地遵循标准的逻辑,“进入编译器的思维”(假设它遵循标准…。@dyp中间的一个,关于函数声明来自何处的相关性。最后一个当然是至关重要的,正如你所说的,但它被称为“函数模板的偏序”,毕竟是有原因的——显式专门化不再是模板,所以这一部分应该非常清楚。
namespace A
{
  template <typename T> struct Foo { };

  template <typename T> void swap (Foo<T> &, Foo<T> &);
}

namespace std
{
  // swap provided by the STL
  template <typename T> void swap (T &, T &);

  // explicit specialization of std::swap
  template <> void swap (Foo<int> &, Foo<intT> &) { }
}
A::swap(Foo<int>&, Foo<int>)&);
std::swap(Foo<int>&, Foo<int>)&);
namespace A
{
  template <typename T> struct Foo { };

  template <typename T> void swap (Foo<T> &, Foo<T> &);

  // explicit specialization of A::swap
  template <> void swap (Foo<int> &, Foo<intT> &) { }
}