为什么C ++元组这么奇怪?

Dun*_*ter 5 c++ tuples c++-standard-library c++11

structs当将不同类型的值分组在一起时,通常会创建自定义。通常这很好,而且我个人觉得命名成员访问更容易阅读,但是我想创建一个更通用的API。在其他语言中广泛使用元组之后,我想返回type的值,std::tuple但是发现在C ++中使用它们比在其他语言中使用起来更加难看。

在使元素访问使用整数模板参数时,需要进行哪些工程决策get

#include <iostream>
#include <tuple>

using namespace std;

int main()
{
    auto t = make_tuple(1.0, "Two", 3);
    cout << "(" << get<0>(t) << ", " 
                << get<1>(t) << ", " 
                << get<2>(t) << ")\n";
}
Run Code Online (Sandbox Code Playgroud)

而不是像下面这样简单的东西?

t.get(0)
Run Code Online (Sandbox Code Playgroud)

要么

get(t,0)
Run Code Online (Sandbox Code Playgroud)

有什么好处?我只看到其中的问题:

  • 像这样使用template参数看起来很奇怪。我知道模板语言是图灵完整的,但所有这些……
  • 如果范围太大,它会使通过运行时生成的索引建立索引变得困难(例如,对于一个小的有限范围索引,我已经看到了使用每种可能性的switch语句编写的代码),或者无法进行索引。

编辑:我已经接受了答案。现在,我已经考虑了语言需要知道的内容以及何时需要知道的内容,我认为这确实有意义。

max*_*x66 10

你说的第二个:

如果范围太大,它会使通过运行时生成的索引建立索引变得困难(例如,对于一个小的有限范围索引,我已经看到了使用每种可能性的switch语句编写的代码),或者无法进行索引。

C ++是一种高度静态的类型化语言,必须确定所涉及的类型编译时

所以一个功能

template <typename ... Ts>
auto foo (std::tuple<Ts...> const & t, std::size_t index)
 { return get(t, index); }
Run Code Online (Sandbox Code Playgroud)

是不可接受的,因为返回的类型取决于运行时值index

采用的解决方案:将索引值作为编译时间值,作为模板参数。

如您所知,我想,它与a完全不同std::array:您有一个get()(方法at(),也有operator[])接收运行时索引值:std::array值类型并不取决于索引。

  • 除非我没有记错,否则这是关于静态类型而不是强类型的。Python也具有强类型(但不是静态类型)。这就是为什么您会在运行时在Python中遇到类型错误的原因,而这种错误在(等效)C ++中会在编译时被捕获,这也是为什么在Python中对元组访问的限制较少。参见https://en.wikipedia.org/wiki/Type_system#Type_checking (5认同)

Max*_*hof 6

需要模板参数的“工程决策”std::get<N>比您想象的要深得多。您正在研究静态类型系统和动态类型系统之间的区别。我建议阅读https://en.wikipedia.org/wiki/Type_system,但这里有一些要点:

  • 在静态类型中,变量/表达式的类型必须在编译时已知。get(int)在这种情况下, 的方法不能std::tuple<int, std::string>存在,因为 的参数get在编译时无法得知。另一方面,由于模板参数必须在编译时已知,因此在这种情况下使用它们是非常有意义的。

  • C++ 也具有多态类形式的动态类型。这些利用运行时类型信息(RTTI),这会带来性能开销。的正常用例std::tuple不需要动态类型,因此它不允许这样做,但 C++ 为这种情况提供了其他工具。
    例如,虽然您不能拥有std::vector包含 和 混合的inta std::string,但您完全可以拥有包含 an和包含 a 的std::vector<Widget*>where ,只要两者都派生自。鉴于,说,IntWidgetintStringWidgetstd::stringWidget

    struct Widget {
       virtual ~Widget();
       virtual void print();
    };
    
    Run Code Online (Sandbox Code Playgroud)

    您可以调用print向量的每个元素,而无需知道其确切(动态)类型。