Ответ 1
Вы не можете использовать std::vector
для auto
. Вместо этого вы можете использовать std:: iterator_traits:
std::vector<typename std::iterator_traits<Iter>::value_type> temp(size);
У меня есть функция шаблона, внутри которой я хочу создать вектор неизвестного типа. Я попытался сделать это автоматически, но компилятор говорит, что это запрещено.
Функция шаблона получает либо итераторы, либо указатели, как показано в тестовой программе внутри следующей основной функции. Как устранить проблему?
template<class Iter>
auto my_func(Iter beg, Iter end)
{
if (beg == end)
throw domain_error("empty vector");
auto size = distance(beg, end);
vector<auto> temp(size); // <--HERE COMPILER SAYS CANNOT BE AUTO TYPE
copy(beg, end, temp->begin);
.
.
return ....
}
int main()
{
int bips[] = {3, 7, 0, 60, 17}; // Passing pointers of array
auto g = my_func(bips, bips + sizeof(bips) / sizeof(*bips));
vector<int> v = {10, 5, 4, 14}; // Passing iterators of a vector
auto h = my_func(v.begin(), v.end());
return 0;
}
Вы не можете использовать std::vector
для auto
. Вместо этого вы можете использовать std:: iterator_traits:
std::vector<typename std::iterator_traits<Iter>::value_type> temp(size);
Если у вас есть совместимый с С++ компилятор, вы можете получить выгоду от вывода аргумента шаблона шаблона.
Итак, если у вас нет конкретной причины для заполнения вашего вектора std::copy
, вы можете написать свой код следующим образом:
template<class Iter>
auto my_func(Iter beg, Iter end)
{
if (beg == end)
throw domain_error("empty vector");
vector temp(beg, end);
// do the remaining stuff
return ....
}
Если эта функция недоступна в вашем компиляторе, я бы проголосовал за
vector<typename iterator_traits<Iter>::value_type> temp(beg, end);
Возможно, вы ищете что-то вроде
std::vector<typename std::remove_reference<decltype(*beg)>::type> temp(beg, end);
Причина auto
не работает, потому что она не разрешена в этом контексте. Вместо аргумента шаблона вы не можете указать auto
. Правильный ход действий, когда вы хотите, чтобы компилятор автоматически выводил аргумент шаблона, - это не предоставление аргумента вообще. Однако в этом случае компилятор не может определить, какой должен быть этот тип. Вы должны указать тип явно.
Есть много способов узнать, какой правильный тип для вашего вектора мы. Вы можете использовать std::iterator_traits
для получения информации об итераторе, включая тип значения, на которое он ссылается. Вы использовали бы typename std::iterator_traits<Iter>::value_type
.
#include <algorithm>
#include <iterator>
#include <stdexcept>
#include <vector>
template<class Iter>
auto my_func(Iter beg, Iter end)
{
if (beg == end)
throw std::domain_error("empty vector");
auto size = std::distance(beg, end);
using t_value = typename std::iterator_traits<Iter>::value_type;
std::vector<t_value> temp(size);
std::copy(beg, end, temp.begin());
return temp;
}
int main()
{
int bips[] = { 3,7,0,60,17 };//Passing pointers of array
auto g = my_func(bips, bips + sizeof(bips) / sizeof(*bips));
std::vector<int> v = { 10,5,4,14 };//Passing iterators of a vector
auto h = my_func(v.begin(), v.end());
return 0;
}
Я хотел бы указать, что нет причин проверять диапазоны 0 размеров. Он корректно вернет пустой вектор.
Вы также можете немного упростить тело my_func
, воспользовавшись тем, что std::vector
имеет конструктор, который принимает пару итераторов и копий, которые имеют диапазон.
template<class Iter>
auto my_func(Iter beg, Iter end)
{
using t_value =typename std::iterator_traits<Iter>::value_type;
return std::vector<t_value>(beg, end);
}
Вы можете извлечь информацию типа указателя / iterator
, используя iterator_traits
. value_type
- это конкретный признак, который вас интересует, поэтому вы можете сделать:
const vector<typename iterator_traits<Iter>::value_type> temp(beg, end);
Неверно, что тип неизвестен. Тип вектора, который вы хотите создать, имеет тот же тип Iter
.
Просто введите Iter
Базовый тип либо с помощью decltype
, либо используя свойство типа итератора следующим образом:
decltype
→ std::vector<typename remove_reference<decltype(*beg)>::type> temp(beg, end);
iterator type trait
следующим образом
using Type = std::iterator_traits<Iter>::value_type;
std::vector<Type>...
Я бы решил это немного по-другому, чем ваш вопрос, кажется, требует.
Во-первых, я считаю, что диапазоны лучше базового типа, чем два итератора. Два итератора связаны друг с другом, они должны быть одним аргументом. Диапазон - это простая структура из двух итераторов с некоторыми полезными методами:
template<class It>
struct range_t:
std::iterator_traits<It>
{
It b{}, e{};
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
auto size() const { return std::distance(begin(), end()); }
// etc
range_t()=default;
range_t(range_t const&)=default;
range_t(range_t &&)=default;
range_t& operator=(range_t const&)=default;
range_t& operator=(range_t &&)=default;
};
template<class It>
range_t<It> make_range( It s, It f ) { return {std::move(s), std::move(f)}; }
range_t
правильно соедините начинающий итератор вместе.
Теперь
template<class Range>
auto my_func(Range&& range) {
// todo
}
template<class Iter>
auto my_func(Iter beg, Iter end)
{
return my_func(make_range(std::move(beg), std::move(end)));
}
- первый шаг. Или просто исключите версию с двумя итераторами целиком и ожидайте, что вызывающий абонент сделает для них свои итераторы.
template<class Range>
auto my_func(Range&& range) {
if (range.empty())
throw domain_error("empty vector");
// todo
}
Итак, теперь вы хотите сделать это:
auto size = range.size();
vector<auto> temp(size);//<--HERE COMPILER SAYS CANNOT BE AUTO TYPE
copy(range.begin(), range.end(), temp->begin);
но это обычная операция. Поэтому мы пишем его для диапазона:
template<class Range>
auto as_vector( Range const& r ) {
using value_type = typename Range::value_type;
std::vector<value_type> v( range.begin(), range.end() );
return v;
}
дает нам:
template<class Range>
auto my_func(Range&& range) {
if (range.empty())
throw domain_error("empty vector");
auto v = as_vector(range);
// ...
return ...;
}
Мы разложили вашу проблему на простые примитивы, имеющие смысл, и переместили сложность реализации в эти примитивы. "Бизнес-логика" вашего my_func
больше не заботится о том, какие шаги вы предпринимаете, чтобы сделать диапазон в вектор.
Это делает ваш my_func
более читабельным, если у вас есть некоторое доверие к тому, что as_vector(range)
действительно возвращает этот диапазон как вектор.