How does boost::ref work? - c++

Having read couples of explanations here on StackOverflow, I still don't have a clue to how it works and what it is for. The demos I saw all use boost::reference_wrapper<int> as the type, that is, they all wrap int, and they also all run prefix op++ to show how it affects the wrapped int in the function template. One expert said the ref wrapper will be cast into the wrapped object if op++ is called on the ref wrapper, but it seems that it's not how it works. Please see the following example that demonstrates what would happen if the wrapped object is not an int. You may want to compile it before reading the code, so as to save your precious time.
// Build int version: g++ thisFile.cpp -Wall
// Build CFoo version: g++ -std=c++11 thisFile.cpp -DDONT_USE_INT -Wall
#include <boost/ref.hpp>
#include <iostream>
using namespace boost;
using namespace std;
class CFoo
{
public:
CFoo(int val) : m_val(val) {}
CFoo& operator++(void) {
++m_val;
return *this;
}
private:
int m_val;
friend ostream & operator<<(ostream& ostrm, const CFoo& param);
};
template <typename T>
void a_func_tmpl(T param)
{
++param;
}
ostream & operator<<(ostream& ostrm, const CFoo& param)
{
ostrm << param.m_val;
return ostrm;
}
int main(int argc, char *argv[])
{
#if defined(DONT_USE_INT)
CFoo obj(0);
#else
int obj(0);
#endif
a_func_tmpl(obj);
cout << obj << endl;
a_func_tmpl(ref(obj));
cout << obj << endl;
return 0;
}
Below is the output of compiling.
$ g++ -std=c++11 thisFile.cpp -Wall
$ ./a.out
0
1
$ g++ -std=c++11 thisFile.cpp -DDONT_USE_INT -Wall
thisFile.cpp: In instantiation of ‘void a_func_tmpl(T) [with T = boost::reference_wrapper<CFoo>]’:
thisFile.cpp:40:22: required from here
thisFile.cpp:22:2: error: no match for ‘operator++’ (operand type is ‘boost::reference_wrapper<CFoo>’)
++param;
^
As you can see, it does work if the wrapped type is int, but a compile-time error happens if the type is not int even if the wrapped type offers op++. It would be highly appreciated (I've been stuck on this for 2 days T_T) if someone can explain what really happens when a method of wrapped type is called on the wrapped ref. Thanks in advance. m(_ _)m

reference_wrapper is really simple, the easiest way to understand how it works is simply to look at the code. The generator functions, ref and cref that create a reference_wrapper are even simpler, again, just look at their definitions.
Understanding what it's for is also pretty simple: the intended use of reference_wrapper is to pass a variable by reference through a generic API that usually takes arguments by value. That's it.
That's useful when you have wrapped some function or functor in a forwarding API, and want to ensure the forwarding API passes references not values.
For instance, boost::bind copies its arguments into the callable object that it returns, and then invokes the target function passing the copied objects as arguments.
e.g. when you call boost::bind(&func, i) it returns a functor that contains a copy of &func and a copy of i. When you invoke that functor, it calls func with the copy of i. So if the function takes a reference, that reference is bound to the internal copy of i not to i itself. So if you have:
void func(int& i) { ++i; }
int i = 0;
auto bound = boost::bind(&func, i);
bound();
assert( i == 1 ); // FAILS!
The assertion will fail, because the int that gets passed to func is not i but a copy of i stored inside bound.
If you actually want the bound function to be called with a reference, you need something that is copyable like a value but implements reference semantics, which is where reference_wrapper comes in:
void func(int& i) { ++i; }
int i = 0;
auto bound = boost::bind(&func, boost::ref(i));
bound();
assert( i == 1 ); // passes
Now ref(i) creates a reference_wrapper<int> that refers to i and so bound contains a copy of that reference_wrapper<int>, also referring to i. When you invoke bound it passes the reference_wrapper<int> to func, which triggers the implicit conversion to int&, so that the reference binds to i, and i gets incremented as desired.
Other examples where you would use reference_wrapper are std::thread and std::async (and the Boost equivalents). They copy their arguments and then pass them to the wrapped target functor as rvalues, so if the functor has lvalue reference parameters then you must use reference_wrapper for the code to even compile.
Using reference_wrapper with your a_func_tmpl example doesn't really match the intended use, because the function doesn't take a reference, and you're not calling it through a generic API that would decay references to value anyway. Personally I wouldn't worry too much about why your example works in one case and not in the other, because it isn't the intended use case for reference_wrapper anyway. It's more important to understand what it is meant for, so you can use it in the appropriate places when necessary.

Your usage and understanding of reference_wrapper<> seems to actually be correct. However, you stumbled over another problem, which obscures that.
The problem is that there is no implicit conversion from reference_wrapper<CFoo> to CFoo& for the implicit this parameter. In this case, this would be needed to find operator++. However, it should work fine with a free-standing function that does the same:
void bar(CFoo& foo)
{
++foo;
}
template <typename T>
void a_func_tmpl(T param)
{
bar(param); // This allows the implicit conversion
}
Alternatively, you can implement operator++ as a free-standing function:
class CFoo
{
public:
CFoo (int val) : m_val (val) {}
private:
int m_val;
friend ostream & operator<<(ostream& ostrm, const CFoo& param);
friend CFoo& operator++(CFoo& foo);
};
CFoo& operator++(CFoo& foo) {
++foo.m_val;
return foo;
}
The only problem really is that the compiler doesn't know that it needs to convert from reference_wrapper<CFoo> to CFoo& to find operator++ if you define it in the class. The conversion is available, but it isn't asked for.

The code fails because ++param is calling boost::reference_wrapper<CFoo>::operator++ (because that's what you passed) for which there is no definition.
The interface of reference_wrapper<T> has a conversion operator to T&, but the compiler does not have a way to deduce that that's what you meant. x++ means 'call x::operator++', not 'find any old version of operator++ that I can coerce x into'
try
++(static_cast<T&>(param))
or
T& p = param;
++p;

Related

How do I write a lambda expression that looks like a method?

I've been going nuts trying to figure this out. Consider the following code (I'm assuming forward references have been defined):
// Signature representing a pointer to a method call
typedef
void (MyClass::*MyMethod)(int);
class MyClass
{
MyClass();
void method1(int i);
void method2(int i);
void associateMethod(int index, MyMethod m);
}
Given the above, the constructor can do things like the following:
MyClass::MyClass()
{
associateMethod(1, &MyClass::method1);
associateMethod(2, &MyClass::method2);
}
However, I'd like to be able to invoke 'associateMethod' where the second parameter is an anonymous method. However, the following doesn't compile.
associateMethod(3, [this](int) -> void { /* some code here */ }
I get an error about their being no viable conversion from the lambda to MyMethod.
I'm wondering if the lambda syntax needs to include 'MyClass' somewhere but random guesses for the lambda expression such as
MyClass::[this](int) -> void {}
or
[this]&MyClass::(int) -> void {}
don't compile.
Would appreciate any pointers (no pun intended)
Thanks
You can't convert a lambda expression to a class member function pointer and there's no valid syntax to make it look like one1.
Instead of a raw function pointer, you should declare the MyMethod as std::function signature (as was mentioned in the comments):
using MyMethod = std::function<void(int)>;
You can use lambdas then to initialize this parameter then:
MyClass::MyClass()
{
associateMethod(1, [this](int a) { this->method1(a); });
associateMethod(2, [this](int a) { this->method2(a); });
}
1)Lambda functions can be thought as compiler generated callable classes, which take the captures as parameters on construction and provide a operator()() overload with the parameters and body you specify. Hence there's no possible valid conversion to a raw or member function pointer.
user0042's answer seems the way to go but, just for completeness sake, it's worth mentioning that in C++17 captureless lambdas have a constexpr conversion operator to their function pointer type, hence you should(*) be able of converting such a lambda to a member function pointer, via something like:
// ...
void associateMethod(int index, MyMethod m);
template<typename F>
void associateMethod(int index, F m) {
associateMethod( index,
static_cast<MyMethod>(
&MyClass::bindFun< static_cast<void(*)(MyClass*,int)>(m) >
) );
}
private:
template<auto F>
void bindFun(int x){ (*F)(this,x); }
// to be used like
x.associateMethod(0,[](MyClass* this_, int x){ this_->method1(x+1); });
(*) sadly, this compiles in clang but gcc refuses to compile it (I'm going to ask a question about this, you can find it here).

How to pass reference to function with lambda

I have a data member that is of type:
std::function<T(T&, T&)>&
The constructor accepts an argument of the same type.
How should I send such a function using lambdas?
I've tried
MyClass tmp([](Foo &a, Foo &b) { return a+b; }, ...);
But it fails.
For example:
main.cpp
#include "MyClass.h"
int main()
{
MyClass a([](int x, int y) { return x+y;});
return 0;
}
MyClass.h
#pragma once
#include <functional>
class MyClass
{
public:
MyClass(std::function<int(int, int)>&) noexcept;
private:
std::function<int(int, int)>& fun;
};
You are passing a lambda to a std::function &. A lambda is not a std::function so that doesn't work directly. However, a lambda is convertible to a std::function, so a temporary std::function has to be build that holds the lambda.
Since you are taking a std::function & C++ assumes you want to modify that value, otherwise there would be no point in taking it by non-const reference. Modifying a temporary has no effect, so this doesn't make sense, so C++ doesn't allow it.
One way to fix the issue is to take a const std::function &. That way there is no modifying of a temporary.
Another way is to pass an actual std::function that you create in main.
Another way is to create a template that just forwards it's argument to the std::function:
class MyClass
{
public:
template <class T>
MyClass(T &&t)
: fun(std::forward<T>(t)){}
private:
std::function<int(int, int)> fun;
};
That way MyClass takes anything and uses it to construct fun. Note that fun is not a reference anymore. The std::function has to live somewhere and since it is part of MyClass it makes sense to tie the lifetime of the std::function to MyClass.
If you really want fun to be a reference you need to find a place for it and make sure it stays there until after MyClass a; gets destroyed. I do not recommend this route since it gets increasingly difficult to make sure the lifetimes are correct.
You can also store the lambda directly, but that is a bit tricky and depending on what you actually want to do with MyClass it may not be viable.

public const doesn't override private const function?

I have a class with a header like this:
public:
const dtMeshTile* getTile(int i) const;
private:
dtMeshTile* getTile(int i);
When I try to use it like this:
const dtMeshTile* const tile = navmesh->getTile(i);
I'm getting a "'dtMeshTile* getTile(int)' is private within this context" How can I specify the public function?
Consider:
#include <cstdlib>
class Bar {};
class Foo
{
public:
Foo (Bar& bar)
:
mBar (bar)
{
}
const Bar& get() const
{
return mBar;
}
private:
Bar& get()
{
return mBar;
}
Bar& mBar;
};
int main()
{
Bar bar;
Foo foo (bar);
Bar& ref = foo.get();
}
At the point of the call: const Bar& ref = foo.get(); you might expect the const version of get() to be called, because you are assigning a const reference.
But this is not the case. Return types are not a part of a function's (or method's) signature, so when the compiler is looking for which function to call in a list of possible overloads, the return type is not considered. (In fact, the Standard rejects function overloads which differ only by return type.)
So, how does the compiler decide which function to call? By looking at the information is does have available to it. The tweo overloads are identical in terms of parameters (both are void), so the only thing it has to go on is the static type of the object used to make the call: foo. That static type in this case is Foo -- decidedly non-const.
Therefore it tried to call the only function it can: the non-const version of get(). Which of course won't compile because that is private.
In order to fox this, the static type can be changed to be a const Foo (or something similar), like this:
Foo foo (bar);
Bar& ref = foo.get();
Or maybe...
Foo foo (bar);
const Bar& ref = static_cast <const Foo&> (foo).get();
But in practice, I would rather advise that the names of these functions be unambigious, rather that relying on such "tricks" to contort the compiler in to doing what you want.
make sure navmesh is const in the context of your call. But I would not recommend const_cast it, you might read this http://www.parashift.com/c++-faq/overview-const.html .
You're hit by a pretty common design flow -- an overload set with mixed semantics.
But I guess you can't change the class, only work around it.
Your problem comes from overload resolution rules. The function is selected based on arguments. Only. private/public stuff is ignored at this stage. The selection happens based on the type before -> if if it's const T*, the first function is selected, for T* the second.
Assess check is applied then, so for the latter case you get the error report. To force the desired function you must use a cast, or better create a free wrapper function
const dtMeshTile* getXXXTile(const XXX* p, int i) {return p->getTitle(i);}
(or a ref-taking variant).
In my codebase the second function would have a different name, as obtaining a mutable string is way different in semantics.

Cast const member function to non-const

Is casting the constness of member function pointers defined in C++? Is the following valid code?
struct T {
void foo(int i) const { std::cout << i << std::endl;};
};
void (T::*f1)(int) const = &T::foo;
void (T::*f2)(int) = reinterpret_cast<void (T::*)(int)>(f1);
T t;
(t.*f2)(1);
Update:
The reason why I need this is that I'm writing a function that accepts both an object and a member function pointer to that object. I need a version for const objects (accepting only const functions) and a normal one. Since I don't want duplicate code, my idea was to put the actual code in the non-const version and call it from the const one, casting away any consts.
Compiler eats it.
But the backward cast is more useful.
And again but - it is better to don't use it, const_cast is usually just a quick and dirty solution, which you apply only when there are not any other solution.
Answer to update
If I understand you correctly you are going to use one object and two function. First function accepts const object and const member-function, second - non-const object and non-const member-function.
According to given information you can change second function to accept non-const object and const member-function. And give them one non-const object and its const member-function.
Yes, it is defined, but you maybe don't want it if the function is really const, because some compiler optimizations (namely return value caching) depend on the function being const.
You can do it, but it has no meaning, wherever you can call f2, you can also call f1 too. You should cast in the other way. But if something, you should cast the object, not the function.
void (T::*f1)(int) const = &T::foo;
void (T::*f2)(int) = reinterpret_cast<void (T::*)(int)>(f1);
T t;
(t.*f2)(1); // compiles
(t.*f1)(1); // this compiles too!!
but if you have
const T t;
(t.*f2)(1); // error t is const
(t.*f1)(1); // still compiles
The only was to resolve the ambiguity is to perform a static_cast, this is basically a language feature
#include <boost/typeof/typeof.hpp>
struct Test
{
const int& foo();
const int& foo() const;
};
int main()
{
typedef const int&(Test::*non_const_ptr)();
typedef const int&(Test::*const_ptr)()const;
BOOST_TYPEOF(static_cast<non_const_ptr>(&Test::foo)) ss;
}
I don't see a reason for doing this: even if you could, you'd make it more restrictive.
Let's say you have a class Foo:
class Foo {
void f() const;
void g();
}
And some snippet of code:
Foo a;
const Foo b;
Then you can call both a.f() and a.g(), but not b.g() because b is const. As you can see, placing const after a member function makes it less restrictive, not more.
And, by reinterpret_casting this pointer, you'll get the pointer with exact same value(due to the nature of reinterpret_cast), and if you try to call it, you'll get into the same T::foo()

Ignore "taking address of temporary" error

For this code
struct test {};
test f() { return test(); }
void print(test *x) {}
int main()
{
print(&f());
print(&test());
}
gcc-4.6 emits two "taking address of temporary [-fpermissive]" errors. This was introduced in 4.6, gcc-4.5 could compile it.
The reason is pretty clear and well documented. The problem is that it is a legacy code and, to compile, we have to make it work, thus, doing #pragmas around files and/or parts of code to compile them with -fpermissive. Let's say, customers are adamant not to modify the existing code (i.e. the fact of calling print() with &f() or &test() cannot be changed, not source files in general). In other words, one way or another this will be compiled, the only choice is more or less pain.
So the question is - are there any possible workarounds to make it work without doing -fpermissive in lots of places? -W flags, C++ tricks, etc.
What I meant is, the fact of calling print() with &f() or &test() cannot be changed.
If you have control over the type itself, you can always overload the reference operator, operator&, and return this from it. It's not a good thing to do in the general case, but it's fairly safe considering that you're returning the correct pointer of the correct type.
If base classes are involved, then it becomes rather more complicated. You'll need to use a virtual operator overload, and each class in the hierarchy will need to implement it separately.
You can provide a workaround by creating an extra print overload that will take a const&:
void print( test const & t ) {
print(&t); // Assuming that the function is 'print( test const * )'
// a print function should not take a non-const pointer!
}
And changing the caller to:
print( f() );
This requires code changes, but in a very limited form, so it might be acceptable. Also note that
Why not just rewrite the code to do exactly what the compiler used to do without complaining? In other words, store your temporary in a temporary (but addressable) variable.
struct test {};
test f() { return test(); }
void print(test *x) {}
int main()
{
test t1 = f();
test t2 = test();
print(&t1);
print(&t2);
}
This should behave identically to the way it did with the old compiler version. Tell the customer that the new compiler requires you to change the code to be explicit about something the compiler used to do implicitly.
It is not clear to me how much control you have over what, but the following hack seems to work:
Edit: Originally had f return a reference instead of a copy. DeadMG correctly points out this leads to undefined behavior as soon as the temporary gets used, so restored f back to returning a copy.
struct test {};
const test & test_copy (const test &t) { return t; }
#define test() test_copy(test())
test f() { return test(); }
#define f() test_copy(f())
void print(const test *) {}
int main()
{
print(&f());
print(&test());
}
The hack is to basically convert your temporaries into const references, so that the compiler will be happier. It shouldn't be made generally available, it's only purpose is to shut the compiler up. But, it doesn't really solve any underlying problems with the customer code or provided API. You could fix your API, and only resort to the hacks for certain customers:
struct test {};
test f() { return test(); }
void print(const test &) {}
#define CUSTOMER_NEEDS_HACK
#ifdef CUSTOMER_NEEDS_HACK
const test & test_copy (const test &t) { return t; }
#define test() test_copy(test())
#define f() test_copy(f())
void print(const test *t) { print(*t); }
#endif