Считаются ли std :: tuple и std :: tuple <std :: tuple> одним и тем же типом с помощью std :: vector?
У меня есть переменная, определенная следующим образом
auto drum = std::make_tuple
( std::make_tuple
( 0.3f
, ExampleClass
, [](ExampleClass& instance) {return instance.eGetter ();}
)
);
Я ожидаю, что drum
будет кортежем кортежа. (т.е. ((a, b, c))
).
И у меня есть другая переменная, определенная следующим образом
auto base = std::make_tuple
( 0.48f
, ExampleClass
, [](ExampleClass& instance) {return instance.eGetter ();}
);
который я ожидаю, чтобы быть просто кортеж из трех элементов (то есть (a, b, c)
)
У меня также есть вектор, определенный следующим образом
std::vector<std::tuple<std::tuple< float
, ExampleClass
, std::function<float (ExampleClass&)>
>>> listOfInstruments;
Теперь, если я добавлю drum
в listOfInstruments
я не ожидаю ошибок.
Что действительно было в случае с listOfInstruments.push_back(drum);
Там, где я ожидал, была ошибка listOfInstuments.push_back(base);
но код компилируется просто отлично.
Поскольку listOfInstruments
имеет тип "кортеж из кортежей", разве добавление "кортежа" не должно вызывать какую-то ошибку? Если оба ()
и (())
не считаются одними и теми же типами в std::vector
. Или я совершенно не прав и тут что-то еще на работе?
Не могу понять это.
Ответы
Ответ 1
Кортежи и векторы здесь в основном красные сельди. Работает только то, что push_back
, как и любая функция, может выполнять неявные преобразования своего аргумента, как показано в следующем рабочем фрагменте:
#include <vector>
struct A { };
struct B {
B(A const &) { }
};
int main() {
std::vector<B> v;
v.push_back(A{});
}
Возвращаясь к кортежу, мы можем видеть, что он имеет (среди прочих) условно-явный конструктор (здесь # 2), который принимает ссылки на будущих членов кортежа:
tuple( const Types&... args );
Этот конструктор является неявным, если и только если все члены имеют неявные конструкторы копирования, что имеет место в данном случае (поскольку синтезированные конструкторы действительно являются неявными). Это означает, что std::tuple<...>
неявно преобразуется в std::tuple<std::tuple<...>>
, что вы и наблюдаете.
Ответ 2
Вектор - это красная сельдь. Суть в том, что std::tuple
имеет (потенциально) конвертирующий конструктор вида:
template< class... UTypes >
tuple( UTypes&&... args );
В нашем случае пакет содержит один элемент decltype(base)
. К счастью, он может быть преобразован в один элемент, хранящийся во внешнем кортеже типа векторного значения.