I have read many posts about variadic templates and std::bind but I think I am still not understanding how they work together. I think my concepts are a little hazy when it comes to using variadic templates, what std::bind is used for and how they all tie together.
In the following code my lambda uses the dot operator with objects of type TestClass but even when I pass in objects of type std::ref they still work. How is this exactly? How does the implicit conversion happen?
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
#include <utility>
using std::forward;
class TestClass {
public:
TestClass(const TestClass& other) {
this->integer = other.integer;
cout << "Copy constructed" << endl;
}
TestClass() : integer(0) {
cout << "Default constructed" << endl;
}
TestClass(TestClass&& other) {
cout << "Move constructed" << endl;
this->integer = other.integer;
}
int integer;
};
template <typename FunctionType, typename ...Args>
void my_function(FunctionType function, Args&&... args) {
cout << "in function" << endl;
auto bound_function = std::bind(function, args...);
bound_function();
}
int main() {
auto my_lambda = [](const auto& one, const auto& two) {
cout << one.integer << two.integer << endl;
};
TestClass test1;
TestClass test2;
my_function(my_lambda, std::ref(test1), std::ref(test2));
return 0;
}
More specifically, I pass in two instances of a reference_wrapper with the two TestClass objects test1 and test2, but when I pass them to the lambda the . operator works magically. I would expect that you have use the ::get() function in the reference_wrapper to make this work but the call to the .integer data member works..
The reference unwrapping is performed by the result of std::bind():
If the argument is of type std::reference_wrapper<T> (for example, std::ref or std::cref was used in the initial call to bind), then the reference T& stored in the bound argument is passed to the invocable object.
Corresponding standardese can be found in N4140 draft, [func.bind.bind]/10.
It is important to note that with std::bind;
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
The "passed by reference" above is achieved because std::ref provides a result of std::reference_wrapper that is a value type that "wraps" the reference provided.
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
By way of an example of what bind's unwrapping of the reference does (without the bind);
#include <iostream>
#include <utility>
#include <functional>
int main()
{
using namespace std;
int a = 1;
auto b = std::ref(a);
int& c = b;
cout << a << " " << b << " " << c << " " << endl; // prints 1 1 1
c = 2;
cout << a << " " << b << " " << c << " " << endl; // prints 2 2 2
}
Demo code.
Related
Sample:
#include "stdafx.h"
#include <functional>
#include <iostream>
#include <string>
std::function<void(int)> Foo()
{
int v = 1;
int r = 2;
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
return l;
}
int main()
{
auto func = Foo();
func(3);
return 0;
}
Why func(3) can pass 3 to i which is the formal argument of the lambda in Foo(). I can't think out. thanks.
TL;DR: You don't pass your argument 3 into a function Foo. You pass it to a method of an object func.
A bit more detailed explanation is below.
First of all, I would like to clarify what a lambda is. A lambda in C++ is nothing more than an anonymous functor class, so essentially just a syntactic sugar. A closure is an instance of a lambda type. However, quite often you can hear words "lambda" and "closure" being used interchangeably.
So within your function Foo() you create a closure object l
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
which would be technically equivalent to this code:
struct Functor
{
Functor(int v, int r) : v_(v), r_(r) {}
void operator ()(int i) const {
std::cout << v_ << " " << r_ << " " << i << std::endl;
}
private:
int v_;
int r_;
};
Functor l(v, r);
Now, on the next line you return an std::function object.
return l; // actually creates std::function<void(int)>(l) and returns it
So in your main function a func is just an object which stores copies of values v, r obtained during a call to Foo() and defines operator(), similar to the struct above.
Therefore, calling func(3) you actually invoke an object method on a concrete object func, and without syntactic sugar it looks like func.operator()(3).
Here's a live example to illustrate my point.
Hope that helps to resolve your confusion.
class Test{
public:
int work(){
cout << "in work " << endl;
return 0;
}
void work(int x){
//cout << "x = " << x << endl;
cout << "in work..." << endl;
}
};
int main(){
Test test;
std::function<void()> f = std::bind(&Test::work, &test);
thread th(f);
th.join();
return 0;
}
As above code, I want to bind member function void work(void) of a class (let's name it Test) , but occurs compiler error saying that can not determine which overrided function to use.
I can not change class Test since it belongs to a lib, how to achieve my goal? Thanks in advance!
Why don't skip std::bind altogether and use a lambda?
auto fp = [&t]() { t.test()};
As a bonus, your executable size will be smaller and your compiler has much easier time to inline the code if appropriate.
By casting it to the correct type:
std::function<void()> f = std::bind( static_cast<int (Test::*)()>(&Test::work), &test);
When deducing the template arguments to bind, the compiler is not in a context that allows function overload resolution - to be simplistic about it, it hasn't got that far yet.
Having deduced that the first argument is indeed the name of a member function pointer, it finds that there are two functions of the same name but of different types.
At this stage, they're both equally valid candidates (from the point of template argument deduction), therefore it's ambiguous
A static cast disambiguates because we're pushing the compiler beyond the stage where it has to deduce a template type - we have taken on the responsibility to template type deduction ourselves - by specifying the type in the static_cast.
So now all it has to do is overload resolution.
#include <functional>
#include <thread>
#include <iostream>
using namespace std;
class Test{
public:
int work(){
cout << "in work " << endl;
return 0;
}
void work(int x){
//cout << "x = " << x << endl;
cout << "in work..." << endl;
}
};
int main(){
Test test;
// only overload resolution required here
auto fp = static_cast<int (Test::*)()>(&Test::work);
// type is now unambiguous and overload resolution is already done
std::function<void()> f = std::bind(fp, &test);
thread th(f);
th.join();
return 0;
}
try this(member function ptr):
int main(){
Test test;
typedef int(Test:: *WKPtr)(void);
WKPtr p = &Test::work;
std::function<int()> f = std::bind(p, &test);
f();
return 0;
}
Minimal working example:
#include <tuple>
struct example
{
example(int, char) {}
};
int main()
{
std::tuple<example, int, double>
my_tuple(example(0, 'x'), 42, .0);
// std::tuple t = make_my_tuple(0, 'x');
return 0;
}
This works.
Is there a more elegant way to initialize only the first member, like I sketched in the comment? One which only takes the arguments to construct the first tuple member and does not initialize the others?
The reason I ask? I am just interested in the semantics of the language.
You say that giving values for the other two members is not necessary - are you worried about performance? Or that there may be no suitable value for these members?
If it's the latter, you could have your tuple hold boost::optionals. e.g.
#include <tuple>
#include <boost/optional.hpp>
using namespace boost;
struct example
{
example(int, char) {}
};
typedef std::tuple<example, optional<int>, optional<double>> MyTuple;
int main()
{
MyTuple my_tuple(example(0, 'x'), optional<int>(), optional<double>());
return 0;
}
You now semantically have the int and float "uninitialised", and can query their value as such.
To make this more elegant, you can wrap this into a function, using the perfect forwarding idiom for the arguments (in general; in this case your arguments are cheap to copy, so no speed benefit from doing this):
template <class... Args>
MyTuple make_mytuple(Args&&... args)
{
return MyTuple(example(std::forward<Args>(args)...), optional<int>(), optional<double));
}
The advantage of this template is that it's resilient to changes in example's constructor. If you add another argument, just call make_mytuple with the new arguments and it will work.
Your other point about the copying in the tuple construction is valid, but in reality I believe this will be optimal on most compilers. (a combination of RVO and elision of copies when passing an rvalue to a function by value).
You can use uniform initialization. Sadly, you cannot define a default value, argument will be initialized with the default constructor or 0.
#include <iostream>
#include <tuple>
enum class Result {Full, Partial, Empty};
std::tuple<bool, int, double> get_tuple(Result type)
{
if (type == Result::Full)
return {true, 42, 3.14159};
else if (type == Result::Partial)
return {true, 42, {}};
else
return {};
}
int main()
{
bool b;
int i;
double d;
std::tie(b, i, d) = get_tuple(Result::Full);
std::cout << b << " " << i << " " << d << std::endl;
std::tie(b, i, d) = get_tuple(Result::Partial);
std::cout << b << " " << i << " " << d << std::endl;
std::tie(b, i, d) = get_tuple(Result::Empty);
std::cout << b << " " << i << " " << d << std::endl;
return 0;
}
output:
1 42 3.14159
1 42 0
0 0 0
It appears that to test for const-ness, one must test the template-parameter, but to test for rvalue-ness, one must test an actual parameter. (This is using VC++ 2012.) This code illustrates what I mean:
#include <type_traits>
#include <string>
#include <iostream>
using namespace std;
template<class T>
void f(T& x) {
cout << "f() is_const<T> and is_const<decltype<x)>" << endl;
cout << is_const<T>::value << endl; // Prints 1 when arg is const
cout << is_const<decltype(x)>::value << endl; // Prints 0 when arg is const
}
template<class T>
void g(T&& x) {
cout << "g() is_const<T> and is_const<decltype<x)>" << endl;
cout << is_const<T>::value << endl; // Prints 0 when arg is const
cout << is_const<decltype(x)>::value << endl; // Prints 0 when arg is cons
cout << "g() is_rvalue_reference<T> and is_rvalue_reverence<decltype(x)>" <<endl;
cout << is_rvalue_reference<T>::value << endl; // Prints 0 when arg is rvlaue
cout << is_rvalue_reference<decltype(x)>::value << endl; // Prints 1 when arg is rvalue
}
int main()
{
const std::string str;
f(str); // const argument
cout << endl;
g(std::string("")); // rvalue argument
return 0;
}
I am struggling to understand why that is. Can someone explain, or point me to an article that explains it? If need be, I will dig into the C++11 standard. Anyone know the pertinent sections?
The reason is that you're misunderstanding things. x will never be const in any of those examples, simply because there are no const reference types (you can't change what a reference refers to anyways). In is_const<T> you're basically ignoring that you declared x as T&.
A similar misunderstanding is at work for the rvalue ref test. The T in T&& (which is called a universal reference, btw) will be deduced as U& when you pass an lvalue and as U when you pass an rvalue. When testing is_rvalue_reference<T>, you're ignoring again that you declared x as T&&. When testing is_const<T>, you didn't account for the fact that T will be a reference, which, as said above, can never be const.
The correct tests for g would be
std::is_const<typename std::remove_reference<T>::type>::value and
std::is_rvalue_reference<T&&>::value
The code below doesn't compile on gcc 4.5 because the call to foo is ambiguous. What is the correct way to disambiguate it?
#include <iostream>
#include <functional>
using namespace std;
void foo(std::function<void(int, int)> t)
{
t(1, 2);
}
void foo(std::function<void(int)> t)
{
t(2);
}
int main()
{
foo([](int a, int b){ cout << "a: " << a << " b: " << b << endl;});
}
The best way is to explicitly create a std::function object of the correct type then pass that object to the function:
std::function<void(int, int)> func =
[](int a, int b) { cout << "a: " << a << " b: " << b << endl; }
foo(func);
or inline:
foo(
std::function<void(int, int)>(
[](int a, int b) { cout << "a: " << a << "b: " << b << endl; }
));
std::function has a constructor template that accepts anything:
template<class F> function(F);
Because of this, there's no way for the compiler to know during overload resolution which foo to select: both std::function<void(int)> and std::function<void(int, int)> have a constructor that can take your lambda expression as an argument.
When you pass a std::function object directly, the std::function copy constructor is preferred during overload resolution, so it is selected instead of the constructor template.
Answer for the future: If the capture list is guaranteed to be empty, you can also use ordinary function pointers. In C++0x, a captureless lambda is implicitly convertible to a function pointer. So, you can use something like
void foo(void (*t)(int, int)) { t(1, 2); }
void foo(void (*t)(int)) { t(1); }
and call foo directly with the captureless lambda (or a function pointer with matching type).
Note that this conversion is a very recent addition to the draft language standard (it was added in February of this year), so it is not likely to be widely supported yet. Visual C++ 2010 doesn't support it yet; I don't know about the latest g++.
I've recently been thinking about a similar problem and when looking around for any known solutions I came across this post and lack of solutions for resolving
An alternative solution is to abstract over the functor as a template argument and use decltype to resolve its type. So, the above example would become:
#include <iostream>
#include <functional>
using namespace std;
template<class F>
auto foo(F t) -> decltype(t(1,2))
{
t(1, 2);
}
template<class F>
auto foo(F t) -> decltype(t(2))
{
t(2);
}
int main()
{
foo([](int a, int b){ cout << "a: " << a << " b: " << b << endl;});
}
This works as expected with gcc 4.5.