C++ template with map allocator problem - c++

I define a template function which loads a map from a CSV file:
template <class T>
bool loadCSV (QString filename, map<T,int> &mapping){
// function here
}
I then try to use it:
map<int, int> bw;
loadCSV<int>((const QString)"mycsv.csv",&bw);
But get htis compile time error:
error: no matching function for call to
‘loadCSV(const QString, std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >*)’
It seems my function call is bringing in some implicit arguments, but I don't understand the error and how to fix it. Any ideas?

Drop the ampersand, you don't want to pass a pointer to the map (notice the asterisk at the end of the error message). Also, you don't have to explicitly cast the string literal. Moreover, the compiler should be able to deduce the template argument automatically.
loadCSV("mycsv.csv", bw);

Related

Multimap insert key typeinfo with std::make_pair vs std::pair constructor

I would like to understand why the following code is valid using std::pair constructor :
Code:
std::multimap< std::type_index, void * > mm;
mm.insert(std::pair<std::type_index, void *>(typeid(int), 0));
And gives compiling error when using std::make_pair:
Error:
C2248 'type_info::type_info' cannot access private member declared in class 'type_info'
Code :
std::multimap< std::type_index, void * > mm;
mm.insert(std::make_pair(typeid(int), 0));
Any clues ? Thank you !
The return type of the typeid is a std::type_info object, which has no constructors defined. As make_pair deduces the template arguments for its output pair from the parameters passed in, it deduces std::pair<std::type_info, int>. It then fails to create the required pair for the above reason.
Your other line creates the pair with explicit template parameters: std::pair<std::type_index, void *>. This time, you are creating an std::type_index object, which does have a constructor, which takes an std::type_info - exactly what you're giving it. So no problems.
Your make_pair line would compile if it was also given explicit template parameters:
mm.insert(std::make_pair<std::type_index, void *>(typeid(int), 0));

How to curry using standard functors

I have the following loop:
MyList li;
vector<Token*>::iterator itr = tokens.begin();
for (; itr != tokens.end(); ++itr) {
li.add_string((*itr)->get_name());
}
I am thinking if I can use functor to replace this loop. One goal here is I could just use standard functor; I do not want to write a separate class just for the purpose of operator().
Here is my version:
for_each(tokens.begin(), tokens.end(),
std::bind1st(std::bind2nd(std::mem_fun(&MyList::add_string),
std::mem_fun(&Token::get_name)),
&li)
);
Unfortunately I get that nasty GCC template compile error.
Can you point me what should be the right functor currying here?
I cannot use c++11.
[EDIT]
My compiler does not support lamda.
Here is the error message if it helps:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h: In instantiation of 'std::binder1st<std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> > >':
abc.c:823: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:100: error: no type named 'second_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:103: error: no type named 'first_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:106: error: no type named 'first_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:111: error: no type named 'second_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:117: error: no type named 'second_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h: In function 'std::binder1st<_Operation> std::bind1st(const _Operation&, const _Tp&) [with _Operation = std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >, _Tp = MyList*]':
abc.c:823: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/backward/binders.h:126: error: no type named 'first_argument_type' in 'class std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> >'
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/algorithm:62,
from abc.c:4:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_algo.h: In function '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<Token**, std::vector<Token*, std::allocator<Token*> > >, _Funct = std::binder1st<std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> > >]':
abc.c:824: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_algo.h:4200: error: no match for call to '(std::binder1st<std::binder2nd<std::mem_fun1_t<void, MyList, const std::string&> > >) (Token*&)'
[EDIT2] I know why I get the error now. bind2nd's implementation is this:
template<typename _Operation, typename _Tp>
inline binder2nd<_Operation>
bind2nd(const _Operation& __fn, const _Tp& __x)
{
typedef typename _Operation::second_argument_type _Arg2_type;
return binder2nd<_Operation>(__fn, _Arg2_type(__x));
}
_Operation is mem_fun_t from MyList::add_string, this is fine because mem_fun_t provides operator() API.
The problem is here: _Arg2_type(__x), because _Arg2_type is _Operation::second_argument_type but mem_fun_t does not have second_argument_type attribute because it is sub-class of unary_function.
Well, if someone could confirming my tracing of type conversion, I'd appreciate it very much.
Thanks Eric, your mentioning "bind1st and bind2d requires the value to be constant" triggers me(but I think your wording is not right per-Se because the key is not the value must be constant, rather the value must be of certain type).
Lastly, GCC extension compose is best solution; I am sure boost has equivalent.
The error comes from the fact you are trying to bind a function as the second parameter for the add_string method of MyList. bind1st and bind2nd requires the value to be constant and are not geared to receive functions as value to bind.
for_each requires a function which takes iterator as first its parameter. What you want to accomplish can't be done without an external function(which is the equivalent of a lambda but not nearly as elegant) if you really insist on using for_each. This function would need to receive the list and token iterator as parameter. You can then bind the list to the function with either bind1st or bind2nd depending on the order in which you declare the parameter.
Let's you have this function:
void AddTokenNameToList(MyList& li, Token* token)
{
li.add_string(token->get_name());
}
You could have this for_each:
for_each(tokens.begin(), tokens.end(), std::bind1st(AddTokenNameToList, li));
If list parameter were inverted, you would use bind2nd instead to bind the list value.
You could argue that this function is custom for this particular case and not as elegant as using only std methods. I guess you could get crazy and template that function to receive method to apply to first parameter and the one for the second but what you really want here is a lambda and since you can't use them, this is as close as you gonna get.
At this point however, you have to wonder if it really saves code. That's one of the reason bind1st and bind2nd have bad rep and considered almost useless. However it lets you use some other nice algorithm so they still have some advantages.
If your compiler supports it, you can use lambdas:
for_each(tokens.begin(), tokens.end(), [&li] (Token * val)
{
li.add_string(val->get_name());
} );

boost::bind with maps, what's the difference between binding std::pair and std::map::value_type?

What's the difference between the following two cases?
std::pair<int,std::string> example_1 (std::make_pair (1,"foo"));
int value_1 = boost::bind (&std::pair<int,std::string>::first,_1) (example_1);
std::map<int,std::string>::value_type example_2 (std::make_pair (2,"boo"));
int value_2 = boost::bind (&std::pair<int,std::string>::first,_1) (example_2);
The first example works fine but the second does not compile when the binding is done. I have looked at the file stl_map.h and value_type is defined as follows:
typedef std::pair<const _Key, _Tp> value_type;
I don't see the difference. I would appreciate is someone can tell let me know and the reason why the second example does not compile.
The compilation error message is:
.../include/boost/bind/mem_fn.hpp:333:36: error: no matching function for call to ‘get_pointer(const std::pair<const int, std::basic_string<char> >&)’
make: *** [main.o] Error 1
Thanks in advance!
The difference is the use of const in the map value type. std::pair<int,std::string>::first is not an accessible item on std::pair<const int,std::string>::first. Yes, there's an implicit conversion defined by pair from the const version to the non-const version, but that conversion isn't considered for the purposes of calling a member function like this. Those uses of pair might look similar, but really they are completely independent classes that are unrelated to each other in terms of where field locations and such might go.
In essence, you'e asked boost to build code like
std::pair<const int,std::string> example(3, "Hello");
example.std::pair<int,std::string>::first
which is not valid.
map's value_type has a const key (const int in your case), whereas the pair you're using doesn't (plain int in your case).

using templates with vectors and vector functions

I am attempting to template a vector. In my main I have the following:
std::vector<Word> concordance = push_vector(data);
Where Word is a struct containing a std::string and an int, and data is a std::string. In my header file I have:
template <typename T>
std::vector<T> push_vector(std::string&);
However when I compile I get the following error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:27:53: error: no matching function for call to ‘push_vector(std::string&)’
main.cpp:27:53: note: candidate is:
templates.h:13:20: note: template<class T> std::vector<T> push_vector(std::string&)
I know I am missing something when I am implementing my template function, but I am not sure what. Thank you for your time in advance.
If I understand what you actually want to do perhaps something more like this:
template <typename T>
void push_vector(const std::string& str, std::vector<T>& vec)
{
// convert str to T if possible
// throw on failure maybe?
// assign vec with converted data
}
Then call it like so:
std::string data("Hello");
std::vector<Word> concordance;
push_vector(data, concordance);
Otherwise you would have to explicitly give the function it's template argument as it can't deduce from the rvalue you are assigning the return value into what the type should be. Not too mention passing an out paramater by reference like this saves you some performance.
Try:
std::vector<Word> concordance = push_vector<Word>(data);
The compiler can't resolve it without a hint because you don't use T anywhere other than the return value. Usually, the template parameter is also used as the type of one (or more) of the template functions' parameters, and then the compiler would be able to resolve it directly.

C++ templates no matching function call

I have a member function of a template class declared as such:
template <class T>
int Data<T>::getPosition(vector<T> stuff, T newStuff, bool ascending)
I call this somewhere with the line
frequencies.insert(frequencies.begin() + getPosition(frequencies, current, ascending),
frequencies[i]);
The variables for that line are declared as:
vector<T> temp;
vector<int> frequencies;
int current = frequency.find(words[i])->second;
However, the call to getPosition gives this error:
Data.h|158|error: no matching function for call to 'primitives::Data<double>::getPosition(std::vector<int, std::allocator<int> >&, int&, bool&)'|
Data.h|165|note: candidates are: int primitives::Data<T>::getPosition(std::vector<T, std::allocator<_CharT> >, T, bool) [with T = double]|
What am I doing wrong here?
getPosition takes three arguments of type vector<T>, T and bool. The templated type T in this case is double (as is shown in the error message), and yet you are trying to pass vector<int> and int as the first and second argument, respectively.
Perhaps the parameters for getPosition should not be templated? Depends on what you are trying to achieve - you do have hard-coded int-vectors there, after all.
Your function prototype gets templated on Data<t>, and it looks like you're performing this call on an object with type Data<double> and passing a std::vector<int> and an int, when it probably expects a std::vector<double> and a double to correspond to the initial templated type of the Data object.
vector<T> temp;
Shouldn't T here be some type like int, double or bool?