C++ 为什么std::pair在赋值中调用显式构造函数
考虑以下代码:C++ 为什么std::pair在赋值中调用显式构造函数,c++,constructor,standards-compliance,explicit,C++,Constructor,Standards Compliance,Explicit,考虑以下代码: #include<iostream> #include<utility> struct Base { int baseint; }; struct Der1 : Base { int der1int; Der1() : der1int(1) {} explicit Der1(const Base& a) : Base(a), der1int(1) { std::cerr <<
#include<iostream>
#include<utility>
struct Base
{
int baseint;
};
struct Der1 : Base
{
int der1int;
Der1() : der1int(1) {}
explicit Der1(const Base& a) : Base(a), der1int(1)
{
std::cerr << "cc1" << std::endl;
}
};
struct Der2 : Base
{
int der2int;
Der2() : der2int(2) {}
explicit Der2(const Base& a) : Base(a), der2int(2)
{
std::cerr << "cc2" << std::endl;
}
};
template <typename T, typename U>
struct MyPair
{
T first;
U second;
};
int main()
{
Der1 d1;
Der2 d2;
std::pair<Der1, int> p1;
std::pair<Der2, int> p2;
p1 = p2; // This compiles successfully
MyPair<Der1, int> mp1;
MyPair<Der2, int> mp2;
mp1 = mp2; // This will raise compiler error, as expected.
}
是符合C++标准的行为吗?乍一看,它看起来前后矛盾,违反直觉。STL的其他实现是否也以同样的方式工作?
快速回答:因为标准要求它应该这样做 当然,你的下一个问题是:标准为什么这么说 想象一下这句话,我认为你同意这句话应该行得通:std::pair<long, long> x = std::make_pair(3, 5);
std::pair x=std::make_pair(3,5);
但是由于3
和5
都是整数,我们试图将std::pair
分配给std::pair
。如果没有模板化构造函数和模板化赋值运算符,它将失败,正如您的MyPair
所证明的那样
所以要回答您的问题:模板化构造函数是为了方便。每个人都希望能够将int分配给long。因此,能够将一对int分配给一对long是合理的。作为类std::pair构造函数的一部分
template<class T1, T2>
class pair
{
public:
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second)
{ }
};
模板
类对
{
公众:
模板
对(常数对和常数对)
:第一(u p.first),
第二(第二)
{ }
};
不是复制构造函数,而是将构造函数从任何对
转换为对
。这适用于第一个
和第二个
成员可转换为另一对的相应成员的情况
根据标准分别转换每个成员。我不确定我是否理解这个问题,但基本上你是在问为什么两个不相关的
std::pair
可以隐式转换,即使实例化类型不能隐式转换。这就是为什么实例化类型的隐式可转换属性不会传播到该对
该标准没有为std::pair
模板提供显式赋值运算符,这意味着它将使用隐式生成的赋值运算符。为了能够分配可转换类型对,它依赖于一个模板构造函数,该构造函数允许从std::pair
隐式转换到std::pair
,其行为在§20.2.2[lib.pairs]/4中定义
template<class U, class V> pair(const pair<U, V> &p);
模板对(const-pair&p);
效果:从参数的相应成员初始化成员,执行隐式con-
根据需要提供不同的版本
标准似乎只要求实现使用隐式转换,而在这个特定的实现中,转换实际上是显式的,这似乎与标准的措词相矛盾。这应该是一个注释,但我更希望有一些空间将其打印出来 因此,假设我们有两种类型:
typedef std::pair<A,B> pairAB;
typedef std::pair<S,T> pairST;
由于std::pair
没有显式赋值运算符,因此我们只能使用默认赋值pairAB&operator=(const pairAB&)
。因此,我们调用隐式转换构造函数,它相当于:
x = pairAB(w); // this happens when we say "x = w;"
但是,已经指出,此转换构造函数调用显式成员构造函数:
pairAB(const pairST & other) : first(other.first), second(other.second) { }
因此,对于每个成员,我们单独使用显式转换。为什么您认为这是不一致和违反直觉的?你反对什么?我认为这是完美的预期行为。您没有显示std::pair赋值运算符。这才是相关的。std::pair赋值运算符没有定义,或者我是瞎子。@konrad rudolph-我没想到在我赋值时会调用显式构造函数。@Steve:哦,对不起,我误解了对
显式
的强调——我正在删除我的注释!我不认为标准要求这样做。看看我的答案。我唯一能引用的是20.2.2,它要求std::pair
隐式转换为std::pair
,根据需要执行隐式转换。该实现实际执行的是显式转换。但是int
隐式转换为long
Der2
可显式转换为Der1
,但不能隐式转换为。我认为如果X
不能隐式转换为Y
,那么pair
就不应该隐式转换为pair
。这个实现并没有实现这一点(我不能马上想到它会是什么样子)。Der2
可以隐式转换为Base
。还有一个Der1
构造函数接受Base
。转换类型时允许一个隐式转换和一个用户定义的转换,因此允许从Der2
转换到Der1
。由于存在显式初始化(如果没有?),显式不禁止此转换。因此,如果不排除显式转换,20.2.2中的“隐式”一词意味着什么?这是否意味着从U
到T1
的转换可以是显式的,但是根据需要执行额外的隐式转换?单独转换每个成员是根据标准的:是的,但是标准将隐式添加到该语句中,在这种情况下,实现是进行显式转换,这就是问题本身的原因。@David你将如何编写这个构造函数?@David-好的,我可能把重点放在这部分而不是赋值或复制构造函数上,而忽略了问题的显式部分。C++0x说,如果成员不是隐式可转换的,则不应考虑此构造函数,但C++98标准没有这样说,并且没有提供任何工具来决定它。不过,您实际如何实现这一点?将\u p.放在初始值设定项列表中的第一个,调用显式构造函数。但如果不这样做,this->first
需要是默认可构造的,这也不符合要求。是否小于鳕鱼
x = pairAB(w); // this happens when we say "x = w;"
pairAB(const pairST & other) : first(other.first), second(other.second) { }