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);
Related
#include <bits/stdc++.h>
#include <vector>
template <typename T>
void g(T&& val)
{
std::vector<T> v;
}
int main()
{
// g(2);
int i;
g(i);
}
When g(2) is called, it complies, but when g(i) is called, the complier has a lot of errors.
Some of the errors are pasted as follows:
forming pointer to reference type ‘int&’
no members matching ‘std::vector<int&, std::allocator<int&> >::_Base {aka std::_Vector_base<int&, std::allocator<int&> >}::_M_allocate’ in ‘std::vector<int&, std::allocator<int&> >::_Base’ {aka ‘struct std::_Vector_base<int&, std::allocator<int&> >’}
no members matching ‘__gnu_cxx::__alloc_traits<std::allocator<int&>, int&>::_Base_type {aka std::allocator_traits<std::allocator<int&> >}::allocate’ in ‘__gnu_cxx::__alloc_traits<std::allocator<int&>, int&>::_Base_type’ {aka ‘struct std::allocator_traits<std::allocator<int&> >’}
forming pointer to reference type ‘int&’
my question:
1. In this case, when the literal value 2 is called, what type is derived for T ?
2. Why doesn't it complie when on i ? How to understand these error messages ?
1: A forwarding reference, and
g(2) makes T an int
g(i) makes T an int&
2: You can't have arrays of references (new T&[x]). You could use std::remove_cvref_t to get the type int out of T:
#include <type_traits>
template <typename T>
void g(T&& val) {
using type = std::remove_cvref_t<T>; // type is int
std::vector<type> v;
}
Your universal reference resolves to int for g(2) and int& for g(i)
You can't have a std::vector of a reference type (see this explanation).
I'm using c++17, and would like to write the code something like this,
#include <variant>
typedef int NewInt;
int main() {
std::variant<NewInt, int> n = 1;
}
But it emits compile error,
po.cpp: In function ‘int main()’:
po.cpp:5:35: error: conversion from ‘int’ to non-scalar type ‘std::variant<int, int>’ requested
std::variant<NewInt, int> n = 1;
^
How could I define the type like std::variant<NewInt, int> or is it impossible?
A type alias is just another name for an existing type, not a new type. So you have a variant of two ints. And while it's allowed, you must address the ambiguity explicitly. std::variant has a suitable constructor:
std::variant<NewInt, int> n{ std::in_place_index<0>, 1 };
The above will construct the first integer member (your NewInt). If you want to construct the second, it's the obvious:
std::variant<NewInt, int> n{ std::in_place_index<1>, 1 };
Background
I have been writing a StateMachine whose transition table is loaded at runtime. The action to take upon each transition is stored as a string. The string is converted to a std::function object that points to a member function of the state machine class. When an event occurs, and results in a transition, that function is invoked.
Problem
I have successfully used this strategy before to decide which function is called at run time. Unfortunately, I've been running into the following error:
error: return type 'XStMachine::TrFunc {aka class std::function<void (XStMachine::*)(const EventData&)>}' is incomplete
Or
invalid use of incomplete type
Steps Taken
I consulted Google and Stackoverflow. I got a number of ideas including taking the definition out of the place where the type is incomplete. Unfortunately, I couldn't get it to work successfully.
I tried using a raw pointer instead of a unique_ptr and found that things worked magically.
I ended up reading a little on the difference between how shared_ptr and unique_ptr handle incomplete types. I tried a shared_ptr, but that did not solve my issue either.
I tried creating a friend class to my state machine in the hope that by the time of the friend class' declaration, the type would be considered whole. I could not get this to work.
Finally, I created the following minimal example (Uncomment code to reproduce the error, please.) which demonstrates the problems I ran into: http://coliru.stacked-crooked.com/a/791092c7ca8fff24 and came to the experts! :)
Source Code
#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <map>
#include <iomanip>
using namespace std;
struct EventData
{
unsigned int x;
};
class Friendly; // Required for compiling the code. Why?
class XStMachine
{
friend class Friendly;
unique_ptr<Friendly> fPtr; //-- Doesn't compile if Friendly is not fwd. declared
unsigned int y;
unsigned int z;
public:
typedef void(XStMachine::*TrFuncPtr)(EventData const&);
typedef std::function<TrFuncPtr> TrFunc;
private:
// map<string, TrFunc> fMap; //-- Doesn't compile because TrFunc is incomplete
// unique_ptr<map<string, TrFunc>> fMap; // Doesn't compile; incomplete type.
map<string, TrFunc> *fMap; // Compiles with incomplete type.
protected:
void tranFunc1(EventData const &d)
{
y = d.x;
}
void tranFunc2(EventData const &d)
{
z = d.x;
}
public:
XStMachine()
{
// Code to init fMap
}
// The code below doesn't compile. incomplete type.
TrFunc getTranFunc(std::string const &s)
{
return (*fMap)[s];
}
~XStMachine()
{
}
};
class Friendly
{
// unique_ptr<map<string, XStMachine::TrFunc> fMap; // Doesn't compile, the type is incomplete.
public:
Friendly()
{
// Code to allocate and init fMap
}
// Dosen't compile if defined here because the return type is incomplete.
//XStMachine::TrFunc& getTranFunc(std::string const&)
//{
// return (*fMap)[s];
//}
};
// The type is incomplete -> Will this work inside a separate cpp file?
//XStMachine::TrFunc& getTranFunc(std::string const &s)
//{
// Weird - Can't access protected members though we're friends. :/
/*
static map<string, XStMachine::TrFunc> fMap = {{"tranFunc1", function(&XStMachine::tranFunc1)},
{"tranFunc2", function(&XStMachine::tranFunc2)}
};
*/
//return fMap[s];
//}
int main() {
cout << "I need to understand incomplete types." << endl;
return 0;
}
Full Error Output from Coliru (gcc 6.3, C++ 14)
main.cpp: In member function 'XStMachine::TrFunc XStMachine::getTranFunc(const string&)':
main.cpp:48:3: error: return type 'XStMachine::TrFunc {aka class std::function<void (XStMachine::*)(const EventData&)>}' is incomplete
{
^
In file included from /usr/local/include/c++/6.3.0/bits/stl_algobase.h:64:0,
from /usr/local/include/c++/6.3.0/bits/char_traits.h:39,
from /usr/local/include/c++/6.3.0/ios:40,
from /usr/local/include/c++/6.3.0/ostream:38,
from /usr/local/include/c++/6.3.0/iostream:39,
from main.cpp:1:
/usr/local/include/c++/6.3.0/bits/stl_pair.h: In instantiation of 'struct std::pair<const std::__cxx11::basic_string<char>, std::function<void (XStMachine::*)(const EventData&)> >':
/usr/local/include/c++/6.3.0/bits/stl_map.h:481:10: required from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::__cxx11::basic_string<char>; _Tp = std::function<void (XStMachine::*)(const EventData&)>; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::function<void (XStMachine::*)(const EventData&)> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::function<void (XStMachine::*)(const EventData&)>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::__cxx11::basic_string<char>]'
main.cpp:49:23: required from here
/usr/local/include/c++/6.3.0/bits/stl_pair.h:196:11: error: 'std::pair<_T1, _T2>::second' has incomplete type
_T2 second; /// #c second is a copy of the second object
^~~~~~
In file included from main.cpp:3:0:
/usr/local/include/c++/6.3.0/functional:1526:11: note: declaration of 'class std::function<void (XStMachine::*)(const EventData&)>'
class function;
^~~~~~~~
Objectives
Primary: Understand what is going on in the example code and fix it.
Secondary: Gain a clear understanding of what an incomplete type is so that I can:
* Solve related problems in the future.
* Know if it is safe to override unique_ptr's default deleter with a deleter that calls the default.
My lack of understanding is really getting in my way here.
Related Questions
Even though Friendly is declared as a friend within XStMachine in the example code, it has to be forward declared earlier in the program as well. Why does this happen?
Even though Friendly is declared a friend, it cannot access protected member functions of XStMachine. For instance, &XStMachine::tranFunc1 is invalid. Why?
std::function takes only a regular function type as template argument. A pointer-to-member-function type doesn't work.
Below is what might be a typical definition of std::function in the standard library:
template< class >
class function; // intentionally undefined
template< class R, class... Args >
class function<R(Args...)> // actual definition
The template argument doesn't determine what kind of function this instantiation can store, but rather how this instantiation can be called.
Any instantiation attempt with a type that is not a regular function type will produce an incomplete type. Example:
std::function <int> incomplete;
In your code you may either:
store std::function<void(EventData const&)> in the map (use std::bind to construct these objects from a pointer-to-member-function and an object pointer); or
do away with std::function altogether and store pointers-to-member-function in the map directly.
I'm trying to implement unordered_map with pointer to custom class as key and integer as value.
I thought pointer is just an address, so I wouldn't have to create comparison template for unordered_map, since map would compare between addresses. But I get compile error.
My code is as follow for simple testing. Can anyone help me to fix what have I done wrong?
#include <cstdlib>
#include <unordered_map>
#include <iostream>
using namespace std;
class MyClass{
public:
MyClass(int id){m_id = id;};
void PrintThis(){cout << " This is test " << endl;};
int m_id;
};
class Test{
public:
unordered_map<MyClass* mc, int test> mapTest;
};
int main(){
MyClass* mc1 = new MyClass(1);
MyClass* mc2 = new MyClass(2);
Test* tt1 = new Test();
tt1->mapTest.insert(make_pair<MyClass*, int>(mc1, 10));
tt1->mapTest.insert(make_pair<MyClass*, int>(mc2, 20));
auto search = tt1->find(mc1);
if(search != tt1->end()) {
search->first->PrintThis();
}else{
cout << "not Found " << endl;
}
}
Error message is as follow
./main.cpp:17:44: error: wrong number of template arguments (1, should be 5)
unordered_map<MyClass* mc, int test> mapTest;
^
In file included from /usr/include/c++/4.8/unordered_map:48:0,
from ./main.cpp:2:
/usr/include/c++/4.8/bits/unordered_map.h:97:11: error: provided for 'template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> class std::unordered_map'
class unordered_map : __check_copy_constructible<_Alloc>
^
./main.cpp: In function 'int main()':
./main.cpp:26:18: error: request for member 'insert' in 'tt1->Test::mapTest', which is of non-class type 'int'
tt1->mapTest.insert(make_pair<MyClass*, int>(mc1, 10));
I think I can manage line 26 error, if line 17 gets fixed...
Thanks in advance!
I tried your code and found 3 problems:
Declaration of map: it should read std::unordered_map<MyClass*, int>
call of undefined functions (tt1->find/tt1->end, should read tt1->testMap.XXX)
Call of make_pair doesn't require template arguments. The compiler will infer them. This actually causes a problem, as the compiler tries to call make_pair(MyClass *&&, int &&). If I omit the template arguments, it works (make_pair(mc1, 10))
As for point 3:
make_pair is declared as follows in C++11 (C++14 just adds constexpr) (cppreference):
template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );
For template argument deduction, the follwing rule applies (cf. cppreference)
4) If P is an rvalue reference to a cv-unqualified template parameter (so-called "forwarding reference"), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of std::forward)
(emphasis mine)
So the compiler will infer:
std::make_pair<MyClass *&, int>(MyClass *&, int &&);
where MyClass *& can bind to your actual argument.
If you directly specify the template types, the compiler will stick to
std::make_pair<MyClass *, int>(MyClass *&&, int &&).
As your argument is a lvalue, it cannot be converted to a rvalue-reference, and compilation fails
Your declaration of unordered_map<MyClass* mc, int test> mapTest; is invalid syntax. It should be unordered_map<MyClass*, int> mapTest.
Also remove the template parameters from your make_pair calls and change tt1->find to ttl->mapTest.find() and ttl->end() to ttl->mapTest.end().
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));