4

考虑以下代码:

#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.
}

在 GCC 4.5.2 下测试

原因在于std::pair来源:

  /** There is also a templated copy ctor for the @c pair class itself.  */
  template<class _U1, class _U2>
    pair(const pair<_U1, _U2>& __p)
    : first(__p.first),
      second(__p.second) { }

该行为是否符合 C++ 标准?乍一看,它看起来不一致且违反直觉。STL 的其他实现是否以相同的方式工作?

4

4 回答 4

5

我不确定我是否理解这个问题,但基本上你是在问为什么std::pair即使实例化类型不可隐式转换,两个不相关的也可以隐式转换。也就是说,为什么实例化类型的隐式可转换属性不会传播到该对。

该标准没有为std::pair模板提供显式赋值运算符,这意味着它将使用隐式生成的赋值运算符。为了能够分配成对的可转换类型,它依赖于允许从to进行隐式转换的模板化构造函数,其行为在 §20.2.2 [lib.pairs]/4 中定义std::pair<A,B>std::pair<C,D>

template<class U, class V> pair(const pair<U, V> &p);

效果:从参数的相应成员初始化成员,根据需要执行隐式转换。

该标准似乎只要求实现使用隐式转换,而在这个特定的实现中,转换实际上是显式的,这似乎与标准的措辞相矛盾。

于 2011-07-20T11:11:54.713 回答
2

作为类 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)
    { } 

};

不是复制构造函数,而是来自任何类型的转换构造函数pair<_U1, _U2>到的转换构造函数pair<T1, T2>。这适用于firstandsecond成员可转换为另一对的相应成员的情况。

分别转换每个成员是根据标准。

于 2011-07-20T11:08:37.947 回答
1

这真的应该是一个评论,但我更喜欢一些空间来输入这个。

所以,假设我们有两种类型:

typedef std::pair<A,B> pairAB;
typedef std::pair<S,T> pairST;

现在我想将一个分配给另一个:

pairAB x;
pairST w;

x = w; // how?

由于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) { }

因此,对于每个成员,我们确实使用显式转换。

于 2011-07-20T11:28:05.713 回答
0

快速回答:因为标准说它应该。

当然,您的下一个问题是:为什么标准会这样说?

想象一下这条线,我认为你同意它应该有效:

std::pair<long, long> x = std::make_pair(3, 5);

但是由于35是整数,我们试图将 a 分配std::pair<int, int>给 a std::pair<long, long>MyPair正如您所证明的,如果没有模板化的构造函数和模板化的赋值运算符,它将失败。

所以回答你的问题:模板化的构造函数是为了方便。每个人都希望能够将 int 分配给 long。因此,能够将一对整数分配给一对长整数是合理的。

于 2011-07-20T11:06:38.303 回答