How to insert a const std::shared_ptr into a std::map - c++

Consider the following code:
#include <string>
#include <map>
#include <memory>
#include <utility>
#include <iostream>
typedef std::shared_ptr<const std::string> ConstDataTypePtr;
typedef std::map<std::string, ConstDataTypePtr> StrDataTypeMap;
int main()
{
StrDataTypeMap m_nameToType;
ConstDataTypePtr vp_int8(new std::string("RGH"));
m_nameToType.insert(std::make_pair<std::string, ConstDataTypePtr>("int8_t", vp_int8));
return 0;
}
You must compile it with: g++ -std=c++11 <filename>.cpp.
It gives the following error:
testO.cpp: In function ‘int main()’:
testO.cpp:14:88: error: no matching function for call to ‘make_pair(const char [7], ConstDataTypePtr&)’
m_nameToType.insert(std::make_pair<std::string, ConstDataTypePtr>("int8_t", vp_int8));
^
testO.cpp:14:88: note: candidate is:
In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:64:0,
from /usr/include/c++/4.8.2/bits/char_traits.h:39,
from /usr/include/c++/4.8.2/string:40,
from testO.cpp:1:
/usr/include/c++/4.8.2/bits/stl_pair.h:276:5: note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
make_pair(_T1&& __x, _T2&& __y)
^
/usr/include/c++/4.8.2/bits/stl_pair.h:276:5: note: template argument deduction/substitution failed:
testO.cpp:14:88: note: cannot convert ‘vp_int8’ (type ‘ConstDataTypePtr {aka std::shared_ptr<const std::basic_string<char> >}’) to type ‘std::shared_ptr<const std::basic_string<char> >&&’
m_nameToType.insert(std::make_pair<std::string, ConstDataTypePtr>("int8_t", vp_int8));
From what I am reading of the error, the compiler is expecting an r-value when I am trying to insert into the map. Why? What mistake have I made here?
Kindly note that I created this snippet from some existing code which is part of a large code-base. It is probably also worth mentioning that the snippet has been taken from a code base which was run on Windows and I have the task of porting it to Linux. The original author had used std::tr1::shared_ptr. I modified it to use std::shared_ptr. I didn't expect any repercussions because of this change.

The whole point of std::make_pair is to let compiler deduce types. If you want to provide type, use std::pair<K, V>
So
m_nameToType.insert(std::make_pair<std::string, std::string>("int8_t", vp_int8));
should be:
m_nameToType.insert(std::make_pair("int8_t", vp_int8));
or
m_nameToType.insert(std::pair<const std::string, ConstDataTypePtr>("int8_t", vp_int8));
or simply:
m_nameToType.emplace("int8_t", vp_int8);

#include <memory>
#include <map>
#include <string>
int main() {
using shared_data = std::shared_ptr<const std::string>;
std::map<std::string, shared_data> map;
map.insert(std::make_pair(
"something",
shared_data(new std::string("something else"))
));
return 0;
}
see: http://ideone.com/4AQfqd
Back to your problem;
testO.cpp:14:83: note: cannot convert ‘vp_int8’ (type ‘ConstDataTypePtr {aka std::shared_ptr >}’) to type ‘std::basic_string&&’
m_nameToType.insert(std::make_pair("int8_t", vp_int8));
What you have:
std::make_pair<std::string, std::string>(some_string, TOTALLY_NOT_A_STRING)

You gave wrong types to the std::make_pair template. Just change
m_nameToType.insert(std::make_pair<std::string, std::string>("int8_t", vp_int8));
Into
m_nameToType.insert(std::make_pair<std::string, ConstDataTypePtr>(std::string("int8_t"), vp_int8));
(note the std::make_pair<std::string, ConstDataTypePtr> part)
EDIT: or don't provide template params at all, as someone suggested in comment.

Don't mention the types in the template in make_pair function.
m_nameToType.insert(std::make_pair("int8_t", vp_int8));

Related

Keying an (unordered_)map using a multimap iterator

I'm building a software where one class is responsible to log info sources and commands (both are grouped as requests), where all requests are inserted inside a multimap, wherein the multimap is keyed by the request name, and each element points to request structure that holds management information and callback function pointer, insighted from this software.
The callbacks are executed to issue a command, or to get an info, and everything is ok until here.
To enable subscription-based information delivery, I've introduced a new map keyed by the request iterator, so where calling subscribe("infoID") the software looks for the exact match request and return its iterator.
Because these iterators are unique per request, I've found it useful to key the subscriptions map using it. Where the key points to info subscriber's callback-functions.
The error is:
error: no match for 'operator<' (operand types are 'const
std::__detail::_Node_iterator<std::pair<const
std::__cxx11::basic_string, request>, false, true>' and 'const
std::__detail::_Node_iterator<std::pair<const
std::__cxx11::basic_string, request>, false, true>')
{ return __x < __y; }
Followed by 15 compiling notes 'template argument deduction/substitution failed':
'const std::__detail::_Node_iterator<std::pair<const
std::__cxx11::basic_string, request>, false, true>' is not
derived from 'const std::pair<_T1, _T2>'
{ return __x < __y; }
each one with a unique source: const std::pair<_T1, _T2>, const std::reverse_iterator<_Iterator> (stl_function.h), const std::reverse_iterator<_Iterator> (stl_iterator.h), ... etc.
Full error here.
Code:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include <functional>
#include <map>
using namespace std;
struct request
{
string f1;
};
using SYS_REQMAP =unordered_multimap<string, request, hash<string>>;
using SYS_REQMAP_I =SYS_REQMAP::iterator;
using SYS_INFOSUB_CBF = function<void(string, string)>;
using SYS_INFOSUB_CBFS = vector<SYS_INFOSUB_CBF>;
using SYS_REQINF_SUBS = map<SYS_REQMAP_I, SYS_INFOSUB_CBFS>;
void cbf(const string& a, const string& b){}
int main()
{
SYS_REQINF_SUBS infoSubr;
SYS_REQMAP vm{{"cmd1", {"foo"}},
{"cmd2", {"bar"}}};
for (SYS_REQMAP_I it = vm.begin(); it != vm.end(); it++)
{
infoSubr[it].push_back(cbf); // Compile error
}
}
void compilesOK()
{
using SYS_REQINF_SUBS_1 = std::map<int, SYS_INFOSUB_CBFS>;
SYS_REQINF_SUBS_1 subs1;
subs1[1].push_back(cbf); // Compiles OK
}
And here's OnlineGDB link to compile and observe output.
The key part of the error is:
stl_map.h:481:32: required from 'std::map<_Key, _Tp, _Compare, ....>
[with _Key = std::__detail::_Node_iterator ....
...
stl_function.h:386:20: error: no match for 'operator<'
std::map (aka ordered map) keys are required to be comparable (operator<), but map iterators are not comparable, and thus cannot be used in an ordered map.
The simpliest solutions is to use some other type.
Other solutions are to provide the map with a comparitor (_Compare), to tell it how to compare iterators, or switch to a unordered_map and provide a hasher to tell it how to hash iterators.
The iterator requires a custom comparison function _Compare:
struct Compare_REQMAP_I
{
bool operator()(const SYS_REQMAP_I& lhs, const SYS_REQMAP_I& rhs) const {
return &lhs < &rhs;
}
};
using SYS_REQINF_SUBS = std::map<SYS_REQMAP_I, SYS_INFOSUB_CBFS, Compare_REQMAP_I>;

no matching function call error using std::find

I have the following function (for testing):
static bool foo(void)
{
std::string name = "name";
std::vector<std::string> test;
std::vector<std::string>::iterator vStart = test.begin();
std::vector<std::string>::iterator vEnd = test.end();
return (std::find(vStart, vEnd, name) == vEnd);
}
And I get a compilation error:
/data/src/fiware-orion/src/lib/common/string.cpp: In function 'bool foo()':
/data/src/fiware-orion/src/lib/common/string.cpp:167:39: error: no matching function for call to 'find(std::vector<std::basic_string<char> >::iterator&, std::vector<std::basic_string<char> >::iterator&, std::string&)'
return (std::find(vStart, vEnd, name) == vEnd);
^
/data/src/fiware-orion/src/lib/common/string.cpp:167:39: note: candidate is:
In file included from /usr/include/c++/4.9/bits/locale_facets.h:48:0,
from /usr/include/c++/4.9/bits/basic_ios.h:37,
from /usr/include/c++/4.9/ios:44,
from /usr/include/c++/4.9/istream:38,
from /usr/include/c++/4.9/sstream:38,
from /data/src/fiware-orion/src/lib/common/string.cpp:31:
/usr/include/c++/4.9/bits/streambuf_iterator.h:369:5: note: template<class _CharT2> typename __gnu_cxx::__enable_if<std::__is_char<_CharT2>::__value, std::istreambuf_iterator<_CharT> >::__type std::find(std::istreambuf_iterator<_CharT>, std::istreambuf_iterator<_CharT>, const _CharT2&)
find(istreambuf_iterator<_CharT> __first,
^
/usr/include/c++/4.9/bits/streambuf_iterator.h:369:5: note: template argument deduction/substitution failed:
/data/src/fiware-orion/src/lib/common/string.cpp:167:39: note: '__gnu_cxx::__normal_iterator<std::basic_string<char>*, std::vector<std::basic_string<char> > >' is not derived from 'std::istreambuf_iterator<_CharT>'
return (std::find(vStart, vEnd, name) == vEnd);
Maybe the message which points to the problem is this:
template argument deduction/substitution failed:
but as far as I undersand the concrete classes used in the find() function argument (std::vector<std::string>::iterator, std::vector<std::string>::iterator and std::string) are clear.
What's specially surprises me is that this same code fragment for foo() function is working verbatim in other parts of my code (i.e. other .cpp files) so maybe it is related somehow with the #include chain in a way I'm not able to deduce or trace...
Any help is welcome!
There is no find from #include <algorithm> in the error message, only the one from streambuf_iterator.h. Add #include <algorithm>.
You are returning an iterator, but your function declaration is 'void'
I think you forgot to include <algorithm>
Please add this #include <algorithm>

Transform a vector of int to a vector of str

I'm trying to convert a vector<int> to a vector<string>. Using std::transform I used std::to_string to convert the int to string but I keep getting an error. Here's my code
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
int main(){
std::vector<int> v_int;
std::vector<std::string> v_str;
for(int i = 0;i<5;++i)
v_int.push_back(i);
v_str.resize(v_int.size());
std::transform(v_int.begin(),v_int.end(),v_str.begin(),std::to_string);
}
but I'm getting this error
no matching function for call to 'transform'
std::transform(v_int.begin(),v_int.end(),v_str.begin(),std::to_string);
^~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:1951:1: note:
candidate template ignored: couldn't infer template argument
'_UnaryOperation'
transform(_InputIterator __first, _InputIterator __last, _OutputIterato...
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:1961:1: note:
candidate function template not viable: requires 5 arguments, but 4 were
provided
transform(_InputIterator1 __first1, _InputIterator1 __last1, _InputItera...
std::to_string is an overloaded function, so you'll need to provide a cast to disambiguate
std::transform(v_int.begin(),v_int.end(),v_str.begin(),
static_cast<std::string(*)(int)>(std::to_string));
Or use a lambda
std::transform(v_int.begin(),v_int.end(),v_str.begin(),
[](int i){ return std::to_string(i); });

no matching function for call to ‘find'

I have the following code:
#include <algorithm>
#include <vector>
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
typedef vector<int> IntContainer;
typedef IntContainer::iterator IntIterator;
IntContainer vw;
IntIterator i = find(vw.begin(), vw.end(), 5);
if (i != vw.end())
{
printf("Find 5 in vector\n"); // found it
}
else
{
printf("Couldn't find 5 in vector\n"); // couldn't found it
}
return 0;
}
I try to compile it on Ubuntu with gcc 4.7.1 and get the following error:
vec_test.cpp: In function ‘int main()’:
vec_test.cpp:27:46: error: no matching function for call to ‘find(std::vector<int>::iterator, std::vector<int>::iterator, int)’
vec_test.cpp:27:46: note: candidate is:
In file included from /usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/locale_facets.h:50:0,
from /usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/basic_ios.h:39,
from /usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/ios:45,
from /usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/ostream:40,
from /usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/iostream:40,
from vec_test.cpp:3:
/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/streambuf_iterator.h:371:5: note: template<class _CharT2> typename __gnu_cxx::__enable_if<std::__is_char<_CharT2>::__value, std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> > >::__type std::find(std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> >, std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> >, const _CharT2&)
/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/streambuf_iterator.h:371:5: note: template argument deduction/substitution failed:
vec_test.cpp:27:46: note: ‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ is not derived from ‘std::istreambuf_iterator<_CharT2, std::char_traits<_CharT> >’
This code doesn't do anything since the vector is not initialized with any content but it should compile.
I suspect this is a gcc problem but after lots of digging I'm quit desperate.
Please let me know if anyone encountered this problem and knows how to solve it.
Maybe some file defines a function find in global namespace?
Have you tried specifying full-scope? That's to say, std::find instead of find. It could help deleting that weird line:
using namespace std;
However, it is not what I would expect. I would call it a bug.

How to use bind1st and bind2nd?

I would like to learn how to use binding functions.
Here is the idea:
I have this function which takes to parameters:
void print_i(int t, std::string separator)
{
std::cout << t << separator;
}
And I would like to do:
std::vector<int> elements;
// ...
for_each(elements.begin(), elements.end(), std::bind2nd(print_i, '\n'));
But it does not work !
Here is what I get:
/usr/include/c++/4.3/backward/binders.h: In instantiation of ‘std::binder2nd<void ()(int, std::string)>’:
main.cpp:72: instantiated from here
/usr/include/c++/4.3/backward/binders.h:138: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:141: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:145: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:149: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:155: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/backward/binders.h:140: error: field ‘std::binder2nd<void ()(int, std::string)>::op’ invalidly declared function type
/usr/include/c++/4.3/backward/binders.h: In function ‘std::binder2nd<_Operation> std::bind2nd(const _Operation&, const _Tp&) [with _Operation = void ()(int, std::string), _Tp = char]’:
main.cpp:72: instantiated from here
/usr/include/c++/4.3/backward/binders.h:164: error: ‘void ()(int, std::string)’ is not a class, struct, or union type
/usr/include/c++/4.3/bits/stl_algo.h: In function ‘_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _Funct = std::binder2nd<void ()(int, std::string)>]’:
main.cpp:72: instantiated from here
/usr/include/c++/4.3/bits/stl_algo.h:3791: error: no match for call to ‘(std::binder2nd<void ()(int, std::string)>) (int&)’
make: *** [all] Error 1
I could use functor, but it is quicker to use binding.
Thanks!
You need to use a Copyable/Refrencable object, the following works:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
void print_i(int t, std::string separator)
{
std::cout << t << separator;
}
int main()
{
std::vector<int> elements;
std::string delim = "\n";
for_each(elements.begin(),
elements.end(),
std::bind2nd(std::ptr_fun(&print_i),delim));
return 0;
}
Normally you can get the same effect by simply doing the following:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> elements;
std::copy(elements.begin(),
elements.end(),
std::ostream_iterator<int>(std::cout,"\n"));
return 0;
}
Also assuming you have access to TR1 in the STL you're using, its always best to revise/replace any uses of bind1st and bind2nd with std::bind
The argument to bind2nd must be an AdaptableBinaryFunction. A plain binary function does not fulfill this requirement (an adaptable function required typedefs for its return and argument types, a plain function type does not provide any typedefs). You could use std::bind which is probably the better choice anyway.
You need to do the following steps:
1. create a struct (or class) that inherits from std::binary_function
2. define your predicate function in the operator() member function of the struct created in step 1
3. use bind2nd to bind an appropriate value to the struct created in step 1
I have done all this in an example. You can read the article and download the complete code on the following link: bind and find
These functions are deprecated since C++11 and removed in C++17. As mentioned in one comment above, the better solution now is to use std::bind and the placeholders:
void callable(int a, int b);
auto f = std::bind1st(&callable, 42); // returns a 1-arg function
becomes:
// returns a 1-arg function
auto f = std::bind(&callable, 42, std::placeholders::_1);