tuple <int, string, int> x=make_tuple(1, "anukul", 100);
cout << x[0]; //1
cout << get<0>(x); //2
2件作品。 1没有。
为什么会这样?
来自Lounge C ++我了解到这可能是因为编译器不知道该索引存储的数据类型。 但它对我来说没有多大意义,因为编译器可以只查找该元组的声明并确定数据类型,或者在通过索引访问其他数据结构元素时执行其他任何操作。
答案 0 :(得分:31)
因为[]是一个运算符(名为>>> d
datetime.datetime(2015, 9, 15, 17, 13, 29, 380000)
>>> d.timestamp()
1442330009.38
>>> import pytz
>>> d.replace(tzinfo=pytz.timezone("US/Eastern")).timestamp()
1442355209.38
),因此是一个成员函数,并在运行时被调用。
虽然获取元组项是模板机制,但必须在编译时解析它。这意味着只能通过&lt;&gt;来完成模板语法。
为了更好地理解,元组可以存储不同的类型。模板函数可能会返回不同的类型,具体取决于传递的索引,因为这是在编译时解决的。 无论传递的参数的值是什么,operator []必须返回唯一类型。因此,元组功能无法实现。
operator[]
和get<0>(x)
是在编译时生成的两个不同的函数,并返回不同的类型。编译器实际上会生成两个函数,这些函数将被修改为类似
get<1>(x)
和
int get_tuple_int_string_int_0(x)
答案 1 :(得分:12)
这里的其他答案解决了为什么无法实现这一问题的问题,但也值得问一下是否应该的问题。 (答案是否定的。)
下标运算符[]
在语义上应该表示对集合元素的动态解析访问,例如数组或列表(任何实现)。访问模式通常意味着某些事情:周围代码可能不知道元素的数量,正在访问的元素可能在运行时变化,并且元素都是相同的可观察类型(因此,对于调用代码) ,可互换)。
事情是,元组不是(那种)集合。它实际上是一个匿名的struct
,它的元素根本不是可互换的插槽 - 从语义上讲,它们是常规字段。可能会让你失望的是它们碰巧被标记为数字,但这实际上只是一种匿名命名模式 - 类似于以x._0
,x._1
等方式访问元素。(你可以计算的事实)字典名称在编译时是由C ++的类型系统启用的巧合奖励,并且与元组的基本没有关系;元组和这个答案并不是真正特定于C ++。)< / p>
所以它不支持operator[]
,原因与普通旧结构不支持operator[]
的原因相同:在此上下文中没有语义有效的用法。结构具有一组固定的字段,这些字段不可互换或可动态计算,并且由于元组是结构而不是集合,因此它遵循相同的规则。它的字段名称看起来不同。
答案 2 :(得分:5)
支持operator[]
不是很干净,因为你不能改变静态返回类型以匹配被访问的元素。如果标准库包含boost::any
或boost::variant
之类的内容,则更有意义。
换句话说,如果你写下这样的话:
int n = atoi(argv[1]);
int x = x[n];
如果n
未解决int
的{{1}}成员,该怎么办?为了支持检查,您需要为tuple
存储某种方式的RunTime类型信息,这是可执行文件/内存中的额外开销。
答案 3 :(得分:4)
可以支持它,它只需要一个编译时索引。由于函数的参数不能成为constexpr
,我们需要将索引包装在一个类型中并传递它。 (例如std::integral_constant<std::size_t, N>
。
以下是支持std::tuple
的{{1}}扩展程序。
operator[]
它会像这样使用:
template <typename... Ts>
class tuple : public std::tuple<Ts...> {
public:
using std::tuple<Ts...>::tuple;
template <std::size_t N>
decltype(auto) operator[](std::integral_constant<std::size_t, N>) {
return std::get<N>(*this);
}
};
为了缓解tuple<int, std::string> x(42, "hello");
std::cout << x[std::integral_constant<std::size_t, 0>{}] << std::endl;
// prints: 42
疯狂,我们可以使用变量模板:
std::integral_constant
有了这个,我们可以说:
template <std::size_t N>
std::integral_constant<std::size_t, N> ic;
所以可以做到。关于为什么目前不可用的一个猜测是因为std::cout << x[ic<1>] << std::endl; // prints: hello
和变量模板等功能可能在std::integral_constant
被引入时不存在。至于为什么即使存在这些特征也不存在,我猜它是因为还没有人提出它。
答案 4 :(得分:1)
因为元组没有操作符“bracket” 为什么会这样?您无法仅根据返回值解析模板。你不能写
template<typename T>
T tuple::operator [](size_t i) const ;
能够允许x[0]
答案 5 :(得分:1)
支持下标运算符(即operator[]
)(例如std::vector
或std::array
)的容器是 齐次 值。无论提供给下标运算符的索引是什么,要返回的值始终是同一类型。因此,这些容器可以使用以下声明来定义成员函数:
T& operator[](int);
T
是集合中每个元素的类型。
另一方面,std::tupe
是 异构 值的集合。 std::tuple
的假定下标运算符的返回值需要随索引而变化。因此,其返回类型取决于索引。
在上面给出的operator[]
的声明中,索引作为函数参数提供,因此可以在运行时确定。但是,函数的返回类型是需要在编译时确定的,而不是在运行时确定的。
由于此类函数的返回类型取决于索引,但必须在编译时确定,因此解决方案是改为定义一个将索引作为(非类型)模板参数。这样,索引作为编译时常量提供,并且返回类型可以随索引而改变:
template<std::size_t I, class... Types>
typename std::tuple_element<I, tuple<Types...>>::type& get(tuple<Types...>&) noexcept;
如您所见,std::get
的返回类型取决于索引I
:
std::tuple_element<I, tuple<Types...>>::type&