std :: pair构造函数接口

时间:2014-03-04 07:32:00

标签: c++ c++11 language-lawyer

这实际上是关于界面设计的一般性问题,但我更容易以std::pair为例:

template <class T1, class T2>
struct pair {
    ...
    pair(const T1& x, const T2& y);
    template<class U, class V> pair(U&& x, V&& y);
    ...
};

所以我们可以看到有两个重载都需要2个参数来初始化该对的2个成员。我的问题是,提供第一个有什么好处,而第二个可用?是否有任何类型的参数只能传递给第一个而不是第二个?

(我们暂时不考虑标准库对后向兼容性的考虑,并讨论接口设计作为一般性问题。)

1 个答案:

答案 0 :(得分:11)

示例实施

template<typename T1, typename T2>
struct simple_pair {
  simple_pair (T1 const& v1, T2 const& v2)  // (1)
    : first  (v1)
    , second (v2)
  { }

  template<class U, class V>     
  simple_pair (U&& v1, V&& v2)              // (2)
    : first  (std::forward<U> (v1))
    , second (std::forward<V> (v2))
  { }

  T1 first;
  T2 second;
};

即使提供重载(1)(2)似乎也是多余的,但有些情况下第二个不可用,第一个不仅是首选而是实际需要。

考虑到我们想要构造我们的一些或两个值,同时将它们传递给simple_pair的构造函数,没有第一次重载,我们将明确地必须再次指定至少一种类型。

T val;

simple_pair<T, U> p1 {   {},   {} }; // only (1) is applicable
simple_pair<T, U> p2 {  val,   {} }; // only (1) is applicable
simple_pair<T, U> p3 { T {}, U {} }; // can use (1) and (2), but this require a lot of typing

替代实施

如果我们改为使用如下所示的实现,我们可以绕过“多余的”重载,因为编译器会知道在这样的信息是什么的情况下我们想要构造什么类型必需的。

template<typename T1, typename T2>
struct simple_pair {
  template<class U = T1, class V = T2>     
  simple_pair (U&& v1, V&& v2)              
    : first  (std::forward<U> (v1))
    , second (std::forward<V> (v2))
  { }

  T1 first;
  T2 second;
};

  T val;

  simple_pair<T, U> p1 {   {},   {} }; // legal
  simple_pair<T, U> p2 {  val,   {} }; // legal
  simple_pair<T, U> p3 { T {}, U {} }; // legal

为什么std::pair声明未使用替代实施方式实施?

我们只能猜测,但可能是因为它具有向后兼容性以及指定它的方式,因此它可以轻松实现库实现者的 1 实现。

通过使用两个单独的重载,可以通过使用宏有条件地添加它来轻松禁用template<class U, class V> simple_pair (U&&, V&&)重载(以查看我们是否使用c++11(或更高版本)),而不是有条件地选择它并且再添一个。


其他潜在原因

  • 从标准中删除某些东西总是很容易做到的......跟随更安全而不是抱歉成语; “如果没有伤害,请将其保留。” - @PlasmaHH

  • 每个人都知道你编写的代码行越多,你就越好的程序员......你就是更好的程序员;得到的报酬越多。


1。 肯定不是很多,但是哎呀..这并不会让人有点迂腐.. ;-)