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
Class 为什么C++;11未能在模板类的构造函数中处理两个模板类型名T==U?_Class_Templates_C++11_Copy Constructor_Move Semantics - Fatal编程技术网

Class 为什么C++;11未能在模板类的构造函数中处理两个模板类型名T==U?

Class 为什么C++;11未能在模板类的构造函数中处理两个模板类型名T==U?,class,templates,c++11,copy-constructor,move-semantics,Class,Templates,C++11,Copy Constructor,Move Semantics,我找不到一个短而好的标题( 假设我有一个简单的C++11模板类定义,如下所示: #include <utility> template <typename T> class A { public: T v; A(){}; template <typename U> A(const A<U>& a); // copy ctor A(A<T>&& a); // move ct

我找不到一个短而好的标题(

假设我有一个简单的C++11模板类定义,如下所示:

#include <utility>

template <typename T>
class A
{
public:
    T v;
    A(){};
    template <typename U>
    A(const A<U>& a); // copy ctor
    A(A<T>&& a); // move ctor
};

template <typename T>
template <typename U>
A<T>::A(const A<U>& a) // copy ctor
{
    v = a.v;
}

template <typename T> // move ctor
A<T>::A(A<T>&& a)
{
    v = std::move(a.v); // although moving PODs does not make sense in my example
}
#include <utility>

template <typename T>
class A
{
public:
    T v;
    A(){};
    template <typename U>
    A(const A<U>& a);
  //  A(A<T>&& a); // removed move ctor
};

template <typename T>
template <typename U>
A<T>::A(const A<U>& a)
{
    v = a.v;
}
#包括
模板
甲级
{
公众:
电视
A(){};
模板
A(常数A&A);//复制
A(A&&A);//移动
};
模板
模板
A::A(常数A&A)//复制
{
v=a.v;
}
模板//move-ctor
A::A(A&&A)
{
v=std::move(a.v);//尽管在我的示例中移动吊舱没有意义
}
现在,我的C++11代码使用了上面的C++11类,如下所示:

int main()
{
    A<char> a;
    A<float> b(a); // okay
    A<char> c(a); // gcc output is as below:
                 // error: use of deleted function 'constexpr A<char>::A(const A<char>&)'
                 // note: 'constexpr A<char>::A(const A<char>&)' is implicitly declared
                 // as deleted because 'A<char>' declares a move constructor or move
                 // assignment operator
    return 0;
}
intmain()
{
A A;
A b(A);//好的
A c(A);//gcc输出如下:
//错误:使用已删除的函数“constexpr A::A(const A&)”
//注意:“constexpr A::A(const A&)”是隐式声明的
//已删除,因为“A”声明了移动构造函数或移动
//赋值运算符
返回0;
}
它给出了使用已删除函数“constexpr A::A(const A&)”的错误

但是,当我在类定义中未使用任何移动语义时,它会正确编译和运行,如下所示:

#include <utility>

template <typename T>
class A
{
public:
    T v;
    A(){};
    template <typename U>
    A(const A<U>& a); // copy ctor
    A(A<T>&& a); // move ctor
};

template <typename T>
template <typename U>
A<T>::A(const A<U>& a) // copy ctor
{
    v = a.v;
}

template <typename T> // move ctor
A<T>::A(A<T>&& a)
{
    v = std::move(a.v); // although moving PODs does not make sense in my example
}
#include <utility>

template <typename T>
class A
{
public:
    T v;
    A(){};
    template <typename U>
    A(const A<U>& a);
  //  A(A<T>&& a); // removed move ctor
};

template <typename T>
template <typename U>
A<T>::A(const A<U>& a)
{
    v = a.v;
}
#包括
模板
甲级
{
公众:
电视
A(){};
模板
A(常数A&A);
//A(A&&A);//已删除
};
模板
模板
A::A(常数A&A)
{
v=a.v;
}
我的问题是:

  • 为什么gcc编译器在这两种情况下对
    模板
    复制ctor中的处理方式不同

  • 为什么在移动ctor存在的情况下,不能处理类型名
    T==U

  • 为什么需要显式编写另一个模板 函数
    模板A::A(常量A&A)
    使用时 移动ctor


  • 您尚未编写副本构造函数。在C++11标准中的
    [class.copy]
    中:

    如果类X的非模板构造函数的第一个参数类型为X&、const X&、volatile X&或const volatile X&,并且没有其他参数,或者所有其他参数都有默认参数,则该类X的非模板构造函数为复制构造函数(8.3.6)

    (我没有看到将模板构造函数称为副本构造函数的规定)

    因此

    如果类定义没有显式声明副本构造函数,则隐式声明副本构造函数

    这两个示例之间的区别在于是否有移动构造函数:

    如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它定义为默认(8.4)


    您尚未编写副本构造函数。在C++11标准中的
    [class.copy]
    中:

    如果类X的非模板构造函数的第一个参数类型为X&、const X&、volatile X&或const volatile X&,并且没有其他参数,或者所有其他参数都有默认参数,则该类X的非模板构造函数为复制构造函数(8.3.6)

    (我没有看到将模板构造函数称为副本构造函数的规定)

    因此

    如果类定义没有显式声明副本构造函数,则隐式声明副本构造函数

    这两个示例之间的区别在于是否有移动构造函数:

    如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它定义为默认(8.4)


    定义移动构造函数会禁用复制构造函数。您需要的是一个转换构造函数,顾名思义,它会将其参数转换为类的类型。如果您的复制/移动构造函数没有做任何特殊的操作,请忽略它们或
    默认值
    它们。要解释您的最后一个困惑,请说明原因伪复制构造函数中的模板参数可能是因为注入的类名。这意味着无论在哪里看到
    A
    ,它都会被
    A
    悄悄替换。为了清楚起见,我将其包括在内

    template <typename T>
    class A
    {
    public:
        T v;
        A() = default;
    
        template <typename U>
        A<T>(const A<U>& a);
    
        A(const A<T>& a) = default;
        A(A<T>&& a) = default;
    };
    
    模板
    甲级
    {
    公众:
    电视
    A()=默认值;
    模板
    A(常数A&A);
    A(常数A&A)=默认值;
    A(A&&A)=默认值;
    };
    
    定义移动构造函数会禁用复制构造函数。您需要的是一个转换构造函数,顾名思义,它会将其参数转换为类的类型。如果您的复制/移动构造函数没有做任何特殊的事情,请忽略它们或
    默认值
    它们。为了解释您的最后一个困惑,请说明您的原因可以忽略伪复制构造函数中的模板参数是因为注入的类名。这意味着无论在哪里看到
    A
    ,它都会以静默方式替换
    A
    。为了清晰起见,我将其包括在内

    template <typename T>
    class A
    {
    public:
        T v;
        A() = default;
    
        template <typename U>
        A<T>(const A<U>& a);
    
        A(const A<T>& a) = default;
        A(A<T>&& a) = default;
    };
    
    模板
    甲级
    {
    公众:
    电视
    A()=默认值;
    模板
    A(常数A&A);
    A(常数A&A)=默认值;
    A(A&&A)=默认值;
    };
    
    对于启动,
    A(常数A&A)“/CODE”不是一个复制构造函数。@ 101010:但是,当t==U.@ SMH时,它使用相同的函数,我相信C++规范明确地表示模板函数不能是复制构造函数。我认为这是因为没有一种简单的方法来确定模板类型最终是否会返回到某种特定类型。@非常感谢!。开始时,
    a(const a&a)“/CODE”不是一个复制构造函数。@ 101010:但是,当t==U.@ SMH时,它使用相同的函数,我相信C++规范明确地表示模板函数不能是复制构造函数。我认为这是因为没有一种简单的方法来确定模板类型最终是否会返回到某种特定类型。@非常感谢!最后的p