Я пытаюсь написать класс-оболочку для декартова итератора продукта, предоставленного Мирандой Конрадо (исходный код можно найти на Гитхаб). Для удобства я также приведу здесь соответствующие фрагменты кода.
Мой класс можно построить двумя способами: один простой, просто перенаправляя контейнеры в конструктор product_iterator
, другой немного сложнее: он берет несколько кортежей, описывающих linspace, необходимое для создания контейнеров, а затем конструирует итератор из их. Именно здесь я зашел в тупик.
Вот некоторый код. Во-первых, некоторые соответствующие заголовки из class product_iterator
Конрадо:
// product_iterator.hpp
template <class... Containers>
class product_iterator:
...
public:
product_iterator();
product_iterator(product_iterator const& other);
product_iterator(Containers const&... containers);
~product_iterator();
product_iterator const& operator=(product_iterator const& other);
....
};
template <class... Containers>
product_iterator<Containers...>
make_product_iterator(Containers const&... containers) {
return product_iterator<Containers...>(containers...);
}
И вот мой класс:
// gridsearch.hpp
typedef std::unordered_map<std::string, Real> result_type;
typedef std::vector<result_type> resultgrid_type;
template <class... Containers>
class GridSearchIterator {
typedef std::array<std::string,
std::tuple_size<std::tuple<Containers...> >::value>
argname_type;
public:
GridSearchIterator() : product_it(product_iterator<Containers...>()),
argnames(argname_type()) {}
GridSearchIterator(const argname_type& names,
const Containers& ...containers);
template <class... TupleTypes>
static GridSearchIterator<Containers...>
initWith(const TupleTypes&& ...tuples);
template<class F, class... Args>
decltype(auto) iterate(F func, Args&&... params);
private:
template <typename TupleType, size_t... Is>
void product_impl(TupleType&& tuples, std::index_sequence<Is...>);
template <typename TupleType>
const auto& unpack_tuple(TupleType& t, size_t index);
product_iterator<Containers...> product_it;
argname_type argnames;
};
// implementation:
template <class... Containers>
GridSearchIterator<Containers...>::GridSearchIterator(
const argname_type& names,
const Containers& ...containers):
product_it(product_iterator<Containers...>(containers...)),
argnames(names) {}
template <class... Containers>
template <typename... TupleTypes>
GridSearchIterator<Containers...> GridSearchIterator<Containers...>::initWith(const TupleTypes&& ...tuples)
{
GridSearchIterator<Containers...> gsi =
GridSearchIterator<Containers...>();
gsi.product_impl(std::tuple<TupleTypes...>(tuples...),
std::index_sequence_for<TupleTypes...>{});
return gsi;
}
template <class... Containers>
template <typename TupleType, size_t... Is>
void GridSearchIterator<Containers...>::product_impl(TupleType&& tuples,
std::index_sequence<Is...>)
{
product_it = product_iterator<Containers...>(
unpack_tuple(std::get<Is>(tuples), Is)...);
// this is where the problem is; Compiler claims No matching constructor for initialization of 'product_iterator...
}
template <class... Containers>
template <typename TupleType>
const auto& GridSearchIterator<Containers...>::unpack_tuple(TupleType &t,
size_t index)
{
std::string argname;
auto left(0), right(0);
Size step;
std::tie(argname, left, right, step) = t;
argnames[index] = argname;
auto vec = linspace(left, right, step);
return static_cast<const decltype(vec) &>(vec);
}
Функция linspace
выше возвращает вектор чисел от left
до right
, равномерно распределенных по количеству step
s. Это эквивалентно функции Numpy np.linspace
.
Я проверил, и вызов unpack_tuple()
действительно создает векторы, необходимые для инициализации product_iterator
, но компилятор не согласен. Я предполагаю, что типы, возвращаемые unpack_tuple()
, несколько отличаются от того, что ожидает конструктор product_iterator
, но я не могу понять, в чем проблема. Или, может быть, проблема на самом деле заключается совсем в другом.
Для лучшего понимания, вот как я использую класс:
{
...
typedef std::tuple<std::string, int, int, size_t> inttuple;
typedef std::tuple<std::string, double, double, size_t> realtuple;
typedef std::vector<int> intvector;
typedef std::vector<Real> realvector;
inttuple sidespan = std::make_tuple("side",1,1,1);
real tuple takeprofit = std::make_tuple("takeprofit",1.,2.,2);
real tuple stoploss = std::make_tuple("stoploss", -1.,-3.,3);
inttuple period = std::make_tuple("horizon", 100, 100, 1);
auto grid_iter = GridSearchIterator<intvector, realvector, realvector, intvector>
::initWith(std::forward<inttuple>(sidespan),
std::forward<realtuple>(takeprofit),
std::forward<realtuple>(stoploss),
std::forward<inttuple>(period));
...
}
Я потратил часы, пытаясь решить эту проблему, поэтому любая помощь или указатели будут высоко оценены, включая советы по другой реализации.
ОБНОВЛЕНИЕ
Извините, я думал, что обновил свой вопрос вчера, но изменения по какой-то причине не были сохранены. Во всяком случае, @ max66 ответил на вопрос даже без дополнительной информации. Тем не менее, для полноты картины, вот определение linspace()
template <typename T>
std::vector<T> linspace(T a, T b, size_t N)
и сообщение компилятора:
В файле, включенном из /.../main.cpp:17:
/.../gridsearch.hpp:98:18: ошибка: нет подходящего конструктора для инициализации'product_iterator<std::__1::vector<int, std::__1::allocator<int> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<int, std::__1::allocator<int> > >' product_it = product_iterator<Containers...>(unpack_tuple(std::get<Is>(tuples), Is)...);
/.../gridsearch.hpp:91:9: примечание: при создании экземпляра шаблона функции здесь запрашивается специализация
'GridSearchIterator<std::__1::vector<int, std::__1::allocator<int> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<int, std::__1::allocator<int> > >::product_impl<std::__1::tuple<std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long> >, 0, 1, 2, 3>'
gsi.product_impl(std::tuple<TupleTypes...>(tuples...), std::index_sequence_for<TupleTypes...>{});
/.../main.cpp:90:88: примечание: при создании экземпляра шаблона функции здесь запрашивается специализация
'GridSearchIterator<std::__1::vector<int, std::__1::allocator<int> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<int, std::__1::allocator<int> > >::initWith<std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, double, double, unsigned long>, std::__1::tuple<std::__1::basic_string<char>, int, int, unsigned long> >'
auto grid_iter = GridSearchIterator<intvector, realvector, realvector, intvector>::initWith(std::forward<inttuple>(sidespan),
В файле из /.../main.cpp:17:
В файле из /.../gridsearch.hpp:22: /.../product_iterator.hpp:73:7: примечание: конструктор-кандидат нежизнеспособно: неизвестно преобразование из'vector<int, allocator<int>>' to 'const vector<double, allocator<double>>'
для 2-го аргументаproduct_iterator(Containers const&... containers);