为什么复制扣除候选人需要作为单独的扣除指南?

时间:2018-05-11 12:57:11

标签: c++ templates c++17 template-deduction argument-deduction

template <typename T> struct A {
    A(T);
    A(const A&);
};

int main()
{
    A x(42); // #1
    A y = x; // #2
}

据我了解,#1的T将使用隐式演绎指南推导出来 从第一个ctor生成。然后使用该ctor初始化x

对于#2,T将使用复制演绎候选人推断(根据我的理解,这是演绎指南的具体情况)(然后y将使用第二个ctor)。

为什么#{1}}不能使用复制文件生成的(隐含)扣除指南推断出#2}?

我想我只是不明白复制演绎候选人的一般目的。

2 个答案:

答案 0 :(得分:12)

添加复制扣除措辞的初稿是P0620R0,提及

  

本文旨在解决

     
      
  • 周一在Kona从EWG进行包装与复制的方向
  •   

有关该会议的一些说明可供参考 https://botondballo.wordpress.com/2017/03/27/trip-report-c-standards-meeting-in-kona-february-2017/

  

复制与包装行为。假设atuple<int, int>类型的变量,我们写tuple b{a};b的类型应该是tuple<int, int>(“复制”行为),还是tuple<tuple<int, int>>(“包装”行为)?这个问题出现在任何类似包装器的类型(例如pairtupleoptional)中,它具有复制构造函数和构造函数,该构造函数接受被包装类型的对象。 EWG认为复制是最好的默认。有一些关于使行为依赖于初始化语法的讨论(例如{ }语法应该总是换行)但是EWG认为在不同初始化语法的行为之间引入新的不一致会带来更多弊大于利。

@kiloalphaindia explained this in a comment

  

如果#2使用A::A(T),我们最终会使用y beeing A<A<int>>。 [...]

这是对的。 A<A<int>>::A(A<int>)构造函数与参数类型完全匹配。另一方面,你也是对的,A<int>::A(const A<int> &)在这种情况下是首选。

但请考虑这个替代方案,其中函数等效显示A<A<int>>如果不是复制扣除候选者则优先选择template <typename T> struct A { A(T &&); A(const A<T> &); }; template <typename T> auto f(T &&) -> A<T>; template <typename T> auto f(const A<T> &) -> A<T>; int main() { A x1(42); // A<int> A y1 = std::move(x1); // A<int> auto x2 = f(42); // A<int> auto y2 = f(std::move(x2)); // A<A<int>> }

import re
var = 'Thomas/Male/'
output = re.search('([\w.-]+)/([\w.-]+)', var)
if output:
    print output.group(1)

答案 1 :(得分:1)

基本问题是,在一般情况下,在知道模板参数并实例化专业化之前,您不知道某些东西是否是复制/移动构造函数,但对于CTAD,您不知道模板争论(duh)并且必须单独通过声明:

template<bool B, class T>
struct A {
   A(std::conditional_t<B, A, int>&); // copy ctor? maybe
   A(std::conditional_t<!B, A&&, char>); // move ctor?

   T t;
   // A(const A&); // implicitly declared? or not? 
                   // is this even the right signature? (depends on T)
   // A(A&&); // implicitly declared? or not?
};
A a = A<true, int>(); // deduce?

复制演绎候选人可以解决这个问题,也可以通过使用按值参数来避免重载决策对价值类别和cv资格的细微处理。