std::tuple get() member function

58

boost::tuple有一个get()成员函数,用法如下:

tuple<int, string, string> t(5, "foo", "bar");
cout << t.get<1>();  // outputs "foo"

看起来C++0x的std::tuple没有这个成员函数,你需要使用非成员函数形式:

std::get<1>(t);

在我看来,这看起来更丑陋。

std::tuple 为什么没有这个成员函数?还是只有我的实现(GCC 4.4)没有?


7
通常情况下,作为设计经验法则,非成员函数应该优先考虑使用。 - GManNickG
3个回答

72

来自C++0x草案:

[注:使用非成员函数的原因是,如果将此功能作为成员函数提供,则依赖于模板参数的类型的代码将需要使用template关键字。 --注解结束]

可以用以下代码说明:

template <typename T>
struct test
{
  T value;
  template <int ignored>
  T&  member_get ()
  {  return value;  }
};

template <int ignored, typename T>
T&  free_get (test <T>& x)
{  return x.value;  }

template <typename T>
void
bar ()
{
  test <T>  x;
  x.template member_get <0> ();  // template is required here
  free_get <0> (x);
};

18
我明白了。不过,如果只是为了与boost兼容(因为许多人可能已经在使用boost元组之前转向C++0x),他们本可以提供成员和非成员函数两种方式,就像boost一样。 - HighCommander4
1
@HighCommander4,虽然我理解你的观点,但仅仅提高兼容性并不足以成为提供新标准的唯一驱动力,因为与现有解决方案的兼容性不应该是提供新标准的唯一驱动力,即使boost也不是最终版本,可能会从一些修订中受益。尽管如此,我仍然同意member-gets是一个好主意。 - Christian Rau
3
既然我们有了不再需要模板关键字的C++11,那我们现在完全可以拥有一个成员函数了吗?只需要一个建议吗? - SwiftMango

34

现有答案非常好,对于标准委员会来说当然至关重要。但我认为还有一个问题很重要,值得一提。

对于自由函数,您可以修改接口,而无需更改类的定义。您可以通过专门化全局 get 来使任何类型“可获取”。对于成员函数,您必须直接修改类。

基于范围的 for 在类类型上查找成员 begin/end,但也通过 ADL 查找非成员 begin/end。这些 API 可以用于任何容器,即使那些没有 begin/end 函数的容器也可以使用。您可以将其专门化为 LibXML2 元素类型,以便您可以在 xmlElement* 上进行基于范围的 for

如果必须是成员函数,则无法这样做。

在 C++ 中,自由函数是许多操作的自然接口,这些操作可能应用于许多不同种类的类。


3
std::begin/std::end 是成员函数和非成员函数优美协作的很好例子,你可以在大多数容器中使用任意一种。 - jakar
好的,这很酷,但是也提供成员函数吧!! - qz-

15

N3090/3092, §20.4.2.6/8: "注意:get是一个非成员函数的原因是,如果将此功能作为成员函数提供,则依赖于模板参数类型的代码将需要使用模板关键字。—注释结束"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接