Alinshans/MyTinySTL

关于 pair 数据结构的相关构造函数的疑问?

wchzh opened this issue · 4 comments

wchzh commented

对于已经定义了下面的copy构造函数:

 // implicit constructiable for other pair

  template <class Other1, class Other2,
    typename std::enable_if<
    std::is_constructible<Ty1, const Other1&>::value &&
    std::is_constructible<Ty2, const Other2&>::value &&
    std::is_convertible<const Other1&, Ty1>::value &&
    std::is_convertible<const Other2&, Ty2>::value, int>::type = 0>
    constexpr pair(const pair<Other1, Other2>& other)
    : first(other.first),
    second(other.second)
  {
  }

为什么还要定义explicit的copy构造函数:

 // explicit constructiable for other pair

template <class Other1, class Other2,
    typename std::enable_if<
    std::is_constructible<Ty1, const Other1&>::value &&
    std::is_constructible<Ty2, const Other2&>::value &&
    (!std::is_convertible<const Other1&, Ty1>::value ||
     !std::is_convertible<const Other2&, Ty2>::value), int>::type = 0>
    explicit constexpr pair(const pair<Other1, Other2>& other)
    : first(other.first),
    second(other.second)
  {
  }

我理解模板参数的含义,就是不知道为什么这样定义,或者可以指出在什么情况下才会调用下面的 explicit的copy构造函数吗。谁能帮忙解答下?谢谢。

首先这不是复制构造函数。

两个重载所要表达的是:如果 Other1Ty1Other2Ty2 存在隐式转换,才提供前一个重载使得 pair<Other1, Other2> 能隐式转换成 pair<T1, T2>。否则 pair<T1, T2> 只能从 pair<Other1, Other2> 显式构造。

这种设计的目的是避免意外地引入“使用隐式转换的方式进行了本来要求为显式的转换”,参见 N4387

萌新求问大佬,为什么要用U替换掉Ty,直接用Ty不是也可以判断是否可以拷贝构造吗?还有pair参数是Ty,U不是一定等于Ty吗,为什么还要判断是否可以隐式转换呢?

// implicit constructiable for this type
template <class U1 = Ty1, class U2 = Ty2,
    typename std::enable_if<
    std::is_copy_constructible<U1>::value&&
    std::is_copy_constructible<U2>::value&&
    std::is_convertible<const U1&, Ty1>::value&&
    std::is_convertible<const U2&, Ty2>::value, int>::type = 0>
    constexpr pair(const Ty1& a, const Ty2& b)
    : first(a), second(b)
{
}

// explicit constructible for this type
template <class U1 = Ty1, class U2 = Ty2,
    typename std::enable_if<
    std::is_copy_constructible<U1>::value&&
    std::is_copy_constructible<U2>::value &&
    (!std::is_convertible<const U1&, Ty1>::value ||
        !std::is_convertible<const U2&, Ty2>::value), int>::type = 0>
    explicit constexpr pair(const Ty1& a, const Ty2& b)
    : first(a), second(b)
{
}

萌新求问大佬,为什么要用U替换掉Ty,直接用Ty不是也可以判断是否可以拷贝构造吗?还有pair参数是Ty,U不是一定等于Ty吗,为什么还要判断是否可以隐式转换呢?

  1. 只有在模板头引入的模板形参带来的替换失败才不是错误。
  2. is_convertible<T, T>::value 不一定对所有对象类型均为 true ,例如 Ty 可以是不支持复制和移动构造的类或是数组。

萌新求问大佬,为什么要用U替换掉Ty,直接用Ty不是也可以判断是否可以拷贝构造吗?还有pair参数是Ty,U不是一定等于Ty吗,为什么还要判断是否可以隐式转换呢?

  1. 只有在模板头引入的模板形参带来的替换失败才不是错误。
  2. is_convertible<T, T>::value 不一定对所有对象类型均为 true ,例如 Ty 可以是不支持复制和移动构造的类或是数组。

非常感谢大佬的回答!如拨云见日,茅塞顿开!让我自己怎么也想不出来😂

所以我自己也试了一下,写了一个简单的例子,如果没有用U替换Ty的话,即使没用到这个函数(下面类A中的f)也会编译报错

template <class T>
class A {
public:
	
	template <class U = T, typename std::enable_if<std::is_copy_assignable<U>::value, int>::type = 0>
	void f() {
		cout<<"!"<<endl;
	}
};