I am trying to write a wrapper class to a Cartesian product iterator provided by Miranda Conrado (source code can be found on GitHub). For convenience I will quote relevant bits of code here, too.
My class can be constructed in two ways - one straightforward, by just forwarding the Containers to the product_iterator constructor, the other is a bit trickier: it takes a number of tuples describing the linspace needed to create the Containers and then constructs the iterator out of them. It is here where I hit a dead-end.
Here is some code.
First, some relevant headers from Conrado's 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...);
}
And here is my class:
// 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);
}
The function linspace above returns a vector of numbers from left to right evenly spaced by number of steps. It is equivalent to Numpy function np.linspace.
I checked and the call to unpack_tuple() does produce the vectors needed to initialise the product_iterator, yet the compiler disagrees. My guess is the types returned by unpack_tuple() are somewhat different from what the product_iterator constructor expects but I can't figure out what is the problem. Or maybe the problem actually lies elsewhere entirely.
For better understanding, here is how I use the class:
{
...
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));
...
}
I spent hours trying to solve it so any help or pointers will be highly appreciated, including advice on different implementation.
UPDATE
Sorry, I thought I updated my question yesterday but the changes were not saved for some reason.
Anyway, #max66 answered the question even without additional info. Still, for completeness, here is the linspace() definition
template <typename T>
std::vector<T> linspace(T a, T b, size_t N)
and compiler message:
In file included from /.../main.cpp:17:
/.../gridsearch.hpp:98:18: error: no matching constructor for initialization of '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: note: in instantiation of function template specialization '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>' requested here gsi.product_impl(std::tuple<TupleTypes...>(tuples...), std::index_sequence_for<TupleTypes...>{});
/.../main.cpp:90:88: note: in instantiation of function template specialization '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> >' requested here auto grid_iter = GridSearchIterator<intvector, realvector, realvector, intvector>::initWith(std::forward<inttuple>(sidespan),
In file included from /.../main.cpp:17:
In file included from /.../gridsearch.hpp:22:
/.../product_iterator.hpp:73:7: note: candidate constructor not viable: no known conversion from 'vector<int, allocator<int>>' to 'const vector<double, allocator<double>>' for 2nd argument product_iterator(Containers const&... containers);
It's difficult to check/verify/propose a correct code if you don't propose a complete example.
Anyway you have the error ("no matching constructor") in this line
product_it = product_iterator<Containers...>(
unpack_tuple(std::get<Is>(tuples), Is)...);
where, if I understand correctly, Containers... is intvector, realvector, realvector, intvector a.k.a. std::vector<int>, std::vector<Real>, std::vector<Real>, std::vector<int> (where I suppose Real is an alias for double).
The only variadic constructor for product_iterator is the one receiving Containers const&... containers so I suppose is the one you want to match.
It seems to me that the problem is that unpack_tuple()
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);
}
return ever a intVector const & (std::vector<int> const &). Also when called with a realVector (std::vector<double>, I suppose).
This (if I'm not wrong) it's because you define left and right as auto and initializing they whit an int
auto left(0), right(0);
you get a couple of int also when TupleType contains Real elements in second and third position.
So when you obtain vec
auto vec = linspace(left, right, step);
you obtain (I suppose) a std::vector<int>; ever; also when you should obtain a std::vector<Real>.
Suggestion: define left and right with the correct type that depends from TupleType.
By example (caution: code not tested)
using lr_type = typename std::tuple_element<1u, TupleType>::type;
lr_type left, right;
Starting from C++14 you can use std::tuple_element_t and the `using can be simplified as follows
using lr_type = std::tuple_element_t<1u, TupleType>;
If you can use C++17, you can use structured binding and all become a lot simpler
template <typename TupleType>
const auto& GridSearchIterator<Containers...>::unpack_tuple(TupleType &t,
size_t index)
{
auto [argname, left, right, step] = t;
argnames[index] = argname;
auto vec = linspace(left, right, step);
return static_cast<const decltype(vec) &>(vec);
}
Off Topic: are you sure that is a good idea unpack_tuple() returning a const reference to a value that is destroyed at the end of execution of the method ?
I'm trying to sort a vector of pairs containing a smart pointers of a const object. I'm trying to sort only depending on the first object. Below you see (one of my numerous attempts to write) code that is supposed to do this, alongside with an excerpt from the error.
The compiler complains about the lambda parameters. I've tried to make the parameters const, non-const, references, rvalue-references, to no avail. Help please?
std::pair<int, std::unique_ptr<const std::string> > a;
auto uniq = std::make_unique<const std::string>("hurz");
a = std::make_pair(1,std::move(uniq));
std::pair<int, std::unique_ptr<const std::string> > b;
uniq = std::make_unique<const std::string>("hurz");
b = std::make_pair(2,std::move(uniq));
std::vector<std::pair<int,std::unique_ptr<const std::string> > > vec;
vec.push_back(std::move(a));
vec.push_back(std::move(b));
std::sort(std::make_move_iterator(vec.begin()),
std::make_move_iterator(vec.end()),
[]
(const std::pair<int,std::unique_ptr<const std::string> >& i1,
const std::pair<int,std::unique_ptr<const std::string> >& i2)
{ return i1.first > i2.first;});
The error message didn't help me:
error: no matching function for call to
'swap(std::move_iterator<__gnu_cxx::__normal_iterator<std::pair<int,
std::unique_ptr<const std::basic_string<char> > >*, std::vector<std::pair<int,
std::unique_ptr<const std::basic_string<char> > > > > >::value_type,
std::move_iterator<__gnu_cxx::__normal_iterator<std::pair<int,
std::unique_ptr<const std::basic_string<char> > >*, std::vector<std::pair<int,
std::unique_ptr<const std::basic_string<char> > > > > >::value_type)' swap(*__a,
*__b);
candidates are:
/usr/include/c++/4.9/bits/move.h:166:5: note: void std::swap(_Tp&, _Tp&)
[with _Tp = std::pair<int, std::unique_ptr<const std::basic_string<char> > >]
plus many more errors in the same vein
The issue here is the use of std::make_move_iterator. When you do so you turn the iterators into move_iterator's which means when you dereference them you get a T&&, instead of a T& like you do with normal iterators.
std::swap, which is used in your implementation of std::sort only takes lvalue references so it cannot bind to the dereferenced iterator. If you use
std::sort(vec.begin(),
vec.end(),
[]
(const std::pair<int,std::unique_ptr<const std::string> >& i1,
const std::pair<int,std::unique_ptr<const std::string> >& i2)
{ return i1.first > i2.first;});
instead then you will have lvalues for std::swap to bind to and std::swap will work for move only types
I add some further explanation to the answer of #NathanOliver which is too long for a comment. I guess the OP's idea of using
std::sort(std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.end()),
[](const std::pair<int,std::unique_ptr<const std::string> >& i1,
const std::pair<int,std::unique_ptr<const std::string> >& i2)
{ return i1.first > i2.first;});
i.e., with a move_iterator applied to vector.begin(), is to use move assignments (and not copies) inside the sorting routine. This idea is tempting, but it's not necessary because inside std::sort, assignments are usually done with std::swap which tries to move arguments passed by reference.
On the other hand, for algorithms which use input and output iterators, such as most basically std::copy or std::copy_if, the use of std::make_move_iterator can be quite useful. Those often use constructs like *output_it = *input_it, and together with std::make_move_iterator this corresponds to *output_it = std::move(*input_it), so the move-assignment operator of the type dereferenced by *output_it could be used.
Currently working with some ol' C++, but am having a touch of trouble with using the greater<int>() comparator for finding the top k keys with the max value in a map.
When compiling receiving the error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:5138:17: error: no matching function for call to object of type 'std::__1::greater<int>'
if (__comp(*__first, *__result_first))
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:5160:12: note: in instantiation of function template specialization 'std::__1::__partial_sort_copy<std::__1::greater<int> &, std::__1::__hash_map_iterator<std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, int>, void *> *> >, std::__1::__wrap_iter<std::__1::pair<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, int> *> >' requested here
return __partial_sort_copy<_Comp_ref>(__first, __last, __result_first, __result_last, __comp);
^
Yikes that's ugly... Here's some context:
Context
I have an unordered_map<vector<string>,int>> construct which I am attempting to find the top k strings in my map which have the max int value.
#include <string>
#include <unordered_map>
#include <algorithm>
#include <functional>
#include <vector>
//...
unordered_map<vector<string>, int> database;
vector<pair <vector<string>, int> > top_k(3);
partial_sort_copy(my_map.begin(),
my_map.end(),
top_k.begin(),
top_k.end(),
greater<int>());
Not the best cpp programmer, would love to hear some suggestions you had to remedy this situation?
According to the documentation on cppreference, the comparator function requires a type signature like so:
bool cmp(const Type1 &a, const Type2 &b);
The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them.
The RandomIt iterators correspond to the top_k structure which when dereferenced has type pair <vector<string>, int>, while std::greater<int> has comparison function of bool operator()( const int& lhs, const int& rhs ). In other words, this does not work because pair <vector<string>, int> does not convert to int.
One solution is to provide your own comparator:
std::partial_sort_copy(my_map.begin(), my_map.end(), top_k.begin(), top_k.end(),
[](const pair<vector<string>, int>& lhs, const pair<vector<string>, int>& rhs) {
return lhs.second > rhs.second;
});
I have difficulty understanding this part of a code? Is it possible to get pictorial/diagram explanation.
//test.h
typedef std::map<std::string, std::string> mType;
static const m_Type::value_type data[] = {
m_Type::value_type("A", "B"),
m_Type::value_type("C", "D"),
m_Type::value_type("E", "F")
};
//test.cc
void test(std::map<std::string, std::string>::value_type data)
{
cout<<data[0].first<<endl;
}
//main.cc
test(data);
In main.cc I wanted to call test() to print elements but getting error
main.cc: In function 'void test(std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >)':
main.cc:10: error: no match for 'operator[]' in 'data[0]'
You have to declare the function the following way
void test( const std::map<std::string, std::string>::value_type data[] )
{
cout<<data[0].first<<endl;
}
because originally data is defined as an array that you are going to pass to the function. Otherwise you may not use the subscript operator.
Also you need to use qualifier const for the parameter because array data also is defined as a constant array.
As for this type
m_Type::value_type
then it is equivalent to std::pair<const std::string, std::string> So this declaration
static const m_Type::value_type data[] = { /*...*/ };
is equivalent to
static const std::pair<const std::string, std::string> data[] = { /*...*/ };
You are supposed to pass to test a value_type not the whole map.
A value_type corresponds to a pair(key, value) and is define like so in stdlib : typedef pair<const Key, Type> value_type;
therefore this data[0]makes no sense. Should be data.first
I am having a problem in some code using type_traits from boost.
It is quite a complex part of the code, but I could isolate the part that gives the compilation error:
template<const size_t maxLen>
class MyString {
public:
typedef boost::conditional<(maxLen > 0), char[maxLen+1], std::string> ObjExternal;
};
template <class T>
class APIBase {
public:
typedef T obj_type;
typedef typename T::ObjExternal return_type;
};
template <class T>
int edit(const T& field, const typename T::return_type& value)
{
return 0;
}
int myFunction()
{
APIBase<MyString<10> > b;
char c[11];
return edit(b, c);
}
This gives the following error:
test.cpp: In function ‘int myFunction()’:
tes.cpp:109: error: no matching function for call to ‘edit(APIBase >&, char [11])’
tes.cpp:100: note: candidates are: int edit(const T&, const typename T::return_type&) [with T = APIBase >]
However, if I change the line with the code
char c[11];
by
MyString<10>::ObjExternal c;
it works. Similarly, if instead I change the line
typedef boost::conditional<(maxLen > 0), char[maxLen+1], std::string> ObjExternal;
by
typedef char ObjExternal[maxLen+1];
it also works. I am thinking that it is a problem with boost::conditional, as it seems it is not being evaluated right. Is there a problem in my code, or there is an alternative that can be used instead of boost::conditional to have this functionality?
I am thinking about using the 2nd option, but then I could not use maxLen as 0.
You need to use the member typedef type provided by conditional and not the conditional type itself.
Change:
typedef boost::conditional<(maxLen > 0),
char[maxLen+1],
std::string> ObjExternal;
to:
typedef typename boost::conditional<(maxLen > 0),
char[maxLen+1],
std::string>::type ObjExternal;