tr1::mem_fn and members with default arguments - c++

I have class with a member function that takes a default argument.
struct Class
{
void member(int n = 0)
{}
};
By means of std::tr1::mem_fn I can invoke it:
Class object;
std::tr1::mem_fn(&Class::member)(object,10);
That said, if I want to invoke the callable member on the object with the default argument, what's the correct syntax?
std::tr1::mem_fn(&Class::member)(object); // This does not work
g++ complains with the following error:
test.cc:17: error: no match for call to ‘(std::tr1::_Mem_fn<void (Class::*)(int)>) (Class&)’
/usr/include/c++/4.3/tr1_impl/functional:551: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
/usr/include/c++/4.3/tr1_impl/functional:556: note: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
Still, the I have the same problem when Class::member is overloaded by members that takes different arguments...

Default functions are bound at call time, but can't be bound into any sort of wrapper implicitly, because of the way they are implemented. When you pass &Class::member, mem_fn only sees a void (Class::*)(int), and can't see the default argument. Using tr1::bind, you can bind the default argument explictly: std::tr1::bind(&Class::member, 0) or you can use it as you would mem_fn, but you can't do both in one object. You would have to write your own wrapper class for that.
As for overloads, you will have to explicitly specify the template arguments for mem_fn so the right function pointer is picked as in mem_fn<void(int)>(&Class::member).

The reason is that any default arguments do not change the function type of a function.
mem_fn has no way to know the function only requires 1 argument, or that the functions' second argument is optional, since all the knowledge it gets is given to it by the type of &Class::member (which stays void(Class::*)(int)) . It therefor requires an integer as the second argument.
If you want to pass the address of a member function overloaded, you have to cast to the right member function pointer type:
static_cast<void(Class::*)()>(&Class::member) instead of just &Class::member, so the compiler has a context to figure out which address is to be taken.
Edit: coppro has a nicer solution how to provide context: std::tr1::mem_fn<void()>(&Class::member)

Related

Error "lambda is not derived from 'std::function'

I'm trying to pass lambda to std::function<> defined via variadic template, but it seems that this doesn't work on gcc.
Is there any reason, why this code doesn't work on gcc 7.4.0 but working correctly on Visual Studio 2017? And is there any way how to make it work also on gcc without the necessity to manually convert it to std::function<> first?
#include <functional>
template<class ...TParams>
int TestFunction(std::function<void(TParams...)> )
{
return 0;
}
void Test()
{
auto fce = [](int /*n*/, double /*d*/) {};
//This doesn't work with error no matching function for call to 'TestFunction<int, double>(Test()::<lambda(int, double)>&)'
TestFunction<int, double>(fce);
//but this works correctly
std::function<void(int, double)> fce2 = fce;
TestFunction<int, double>(fce2);
}
I'm getting following error:
main.cpp: In function 'void Test()':
main.cpp:116:31: error: no matching function for call to 'TestFunction<int, double>(Test()::<lambda(int, double)>&)'
TestFunction<int, double>(fce);
^
main.cpp:106:5: note: candidate: template<class ... TParams> int TestFunction(std::function<void(TParams ...)>)
int TestFunction(std::function<void(TParams...)> fceCallback)
^~~~~~~~~~~~
main.cpp:106:5: note: template argument deduction/substitution failed:
main.cpp:116:31: note: 'Test()::<lambda(int, double)>' is not derived from 'std::function<void(TParams ...)>'
TestFunction<int, double>(fce);
^
A trailing template parameter pack always leaves room for further deduction. Specifying the first two arguments doesn't prevent you from doing something like this:
std::function<void(int, double, char)> fce3 ;
TestFunction<int, double>(fce3);
In this case, the pack will contain int, double, char, because the char was deduced from the function argument. Now, because deduction isn't over, and a lambda is not a std::function, the substitution fails.
To make this work, you need to let the deduction process know it's over, that an instantiated function is needed now, before it's given an argument. One way to do that is to take the function's address, for instance:
auto pfunc = TestFunction<int, double>;
pfunc(fce);
or
(&TestFunction<int, double>)(fce);
Taking a function template's address is another context where template argument deduction can occur. In this case, the trailing pack is deduced as empty, and you get a pointer to a function you may call.

partial_sort and smart pointers

I have a SetPartitionVector class which is derived from vector<SetPartition>. I'd like to partial_sort this vector using a custom comparison function but I have an error at compilation.
bool ScalableSummary::featuresDistComp(SetPartition cluster1, SetPartition cluster2){
return (segmentClusters.AverageSOD(cluster1) > segmentClusters.AverageSOD(cluster2));
}
void ScalableSummary::selectLeastConsensualFeatures(const int p){
partial_sort(segmentClusters.begin(), segmentClusters.begin() + p, segmentClusters.end(), featuresDistComp);
}
segmentClusters is a member of ScalableSummary of type SetPartitionVector which was filled this way :
SetPartition_ptr cluster;
...
segmentClusters.push_back(*cluster);
SetPartition_ptr is a smart pointer defined like this :
typedef boost::shared_ptr<SetPartition> SetPartition_ptr;
This is the error I get from the compiler :
g++ -o ScalableSummary.o -c ScalableSummary.cpp -Iinclude -Wall -g
ScalableSummary.cpp: In member function ‘void ScalableSummary::selectLeastConsensualFeatures(int)’:
ScalableSummary.cpp:56:108: erreur: no matching function for call to ‘partial_sort(std::vector<SetPartition>::iterator, __gnu_cxx::__normal_iterator<SetPartition*, std::vector<SetPartition> >, std::vector<SetPartition>::iterator, <unresolved overloaded function type>)’
ScalableSummary.cpp:56:108: note: candidates are:
/usr/include/c++/4.6/bits/stl_algo.h:5240:5: note: template<class _RAIter> void std::partial_sort(_RAIter, _RAIter, _RAIter)
/usr/include/c++/4.6/bits/stl_algo.h:5279:5: note: void std::partial_sort(_RAIter, _RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<SetPartition*, std::vector<SetPartition> >, _Compare = bool (ScalableSummary::*)(SetPartition, SetPartition)]
/usr/include/c++/4.6/bits/stl_algo.h:5279:5: note: no known conversion for argument 4 from ‘<unresolved overloaded function type>’ to ‘bool (ScalableSummary::*)(SetPartition, SetPartition)’
The function object you pass to std::partial_sort needs to be either a callable object, or a function pointer. To make a function pointer you nedd to use the address-of operator &, just like when you make a pointer out of any other variable:
partial_sort(..., &featuresDistComp);
// ^
// |
// Note address-of operator here
Also, I hope your function is marked as static? You can't use non-static member functions as ordinary function pointers. The reason is that all non-static member functions have a hidden first arguments that is the this pointer inside the function. So either make sure the function is static or use e.g. std::bind:
using namespace std::placeholders; // for _1, _2, _3...
partial_sort(..., std::bind(&ScalableSummary::featuresDistComp, this, _1, _2));

call of an object of a class type without appropriate operator()

I have this following function to test out thrust but it doesn't compile. It appears my predicate is not valid and my knowledge of C/C++ is not strong enough to know what I need to do correct the compilation issue. Please could someone explain what's going on here and how I can fix it.
void filter(device_vector<int>& x,
device_vector<int>& y,
thrust::unary_function<int,bool> f) {
thrust::copy_if(x.begin(), x.end(), y.end(), f);
}
nvcc -o test test.cu -O2
/usr/lib/nvidia-cuda-toolkit/include/thrust/detail/internal_functional.h(102): error: call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
detected during:
instantiation of "__nv_bool thrust::detail::predicate_to_integral<Predicate, IntegralType>::operator()(const T &) [with Predicate=thrust::unary_function<__nv_bool, int>, IntegralType=std::ptrdiff_t, T=int]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/detail/function.h(187): here
instantiation of "Result thrust::detail::host_device_function<Function, Result>::operator()(const Argument &) const [with Function=thrust::detail::predicate_to_integral<thrust::unary_function<__nv_bool, int>, std::ptrdiff_t>, Result=std::ptrdiff_t, Argument=thrust::device_reference<int>]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/iterator/transform_iterator.h(306): here
instantiation of "thrust::detail::transform_iterator_base<AdaptableUnaryFunction, Iterator, Reference, Value>::type::reference thrust::transform_iterator<AdaptableUnaryFunction, Iterator, Reference, Value>::dereference() const [with AdaptableUnaryFunction=thrust::detail::predicate_to_integral<thrust::unary_function<__nv_bool, int>, std::ptrdiff_t>, Iterator=thrust::detail::normal_iterator<thrust::device_ptr<int>>, Reference=std::ptrdiff_t, Value=thrust::use_default]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/iterator/iterator_facade.h(128): here
instantiation of "Facade::reference thrust::iterator_core_access::dereference(const Facade &) [with Facade=thrust::transform_iterator<thrust::detail::predicate_to_integral<thrust::unary_function<__nv_bool, int>, std::ptrdiff_t>, thrust::detail::normal_iterator<thrust::device_ptr<int>>, std::ptrdiff_t, thrust::use_default>]"
/usr/lib/nvidia-cuda-toolkit/include/thrust/iterator/iterator_facade.h(305): here
Let's look at some reference first:
The function object pred shall not apply any non-constant function
through the dereferenced iterator. This function object may be a
pointer to function or an object of a type with an appropriate
function call operator.
From "Predicate".
Thus, you shouldn't limit the choices of the caller to unary_function. In a case like this, any object, function, whatever that can be used in the context of copy_if should be allowed to pass. Actually, in vanilla C++ unary_function is deprecated (in favor of std::function, which shouldn't be used here anyway for exactly the same reasons).

using comparing function

I have this function
std::vector <std::vector <int> > puddles;
std::set <int> is_checked;
size_t M, N;
bool v_compare(int a, int b){
return puddles[(a-a%M)/M][a%M] < puddles[(b-b%M)/M][b%M];
}
and I want to find the set element which corresponds to the minimal value in puddles (I use i*M+j as a key in the set). So I am trying to use my function as a predicate for min_element
close(*std::min_element(is_checked.begin(), is_checked.end(), v_compare));
but I got this error
:113:82: error: no matching function for call to 'min_element(std::set<int>::iterator, std::set<int>::iterator, <unresolved overloaded function type>)'
:113:82: note: candidates are:
/usr/include/c++/4.6/bits/stl_algo.h:6173:5: note: template<class _FIter> _FIter std::min_element(_FIter, _FIter)
/usr/include/c++/4.6/bits/stl_algo.h:6201:5: note: _FIter std::min_element(_FIter, _FIter, _Compare) [with _FIter = std::_Rb_tree_const_iterator<int>, _Compare = bool (TFlood::*)(int, int)]
/usr/include/c++/4.6/bits/stl_algo.h:6201:5: note: no known conversion for argument 3 from '<unresolved overloaded function type>' to 'bool (TFlood::*)(int, int)'
There is a difference between a pointer to function and a pointer to member function. A class member which is not static gets you a pointer to member function. But std::min_element only accepts a pointer to function or other callable type, and a pointer to member function doesn't qualify since it can't be called without a pointer or reference to a class object. And as you found, if you try making the function a static member, then it can't get at the member M. (Maybe puddles too, if that's also a member.)
It looks like you're using g++ 4.6, which supports lambdas. So the easiest solution is:
close(*std::min_element(is_checked.begin(), is_checked.end(),
[this](int a, int b) { return puddles[a/M][a%M] < puddles[b/M][b%M]; }));
(I got rid of the subtractions, since division of integer types always rounds toward zero, so (a-(a%M))/M is always the same result as a/M.) Make sure you use the -std=c++0x compiler flag. The lambda magic takes care of "capturing" the this pointer for later use by the comparison object.

Deficiency in std::mem_fn compared to hand-rolled functor

I have come across a use case where std::mem_fn cannot do something that a hand-rolled wrapper function can. It comes up when the wrapper function is used on something that's not of the method's class, but a type implicitly convertible to it:
#include <functional>
struct A
{
};
struct B
{
B(A); // implicit conversion from A to B
void foo() const;
};
auto foo1 = std::mem_fn(&B::foo); // std::mem_fn
void foo2(const B& b) { b.foo(); } // hand-rolled wrapper
int main()
{
A a;
foo1(a); // doesn't work
foo2(a); // works fine
}
The compiler error for the call to foo1 is the following (with GCC 4.8):
In file included from test.cpp:1:0:
functional: In instantiation of '_Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)const>::_M_call(_Tp&, const volatile void*, _ArgTypes ...) const [with _Tp = A; _Res = void; _Class = B; _ArgTypes = {}]':
functional:608:42: required from '_Res std::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)const>::operator()(_Tp&, _ArgTypes ...) const [with _Tp = A; _Res = void; _Class = B; _ArgTypes = {}]'
test.cpp:21:11: required from here
functional:586:13: error: no match for 'operator*' (operand type is 'A')
{ return ((*__ptr).*__pmf)(std::forward<_ArgTypes>(__args)...); }
^
Would it have been possible to implement std::mem_fn in such a way that this use case works just like it does with the hand-rolled wrapper?
It would be possible, yes, but it's not how the C++ standard specifies mem_fn.
The standard says that foo1(a) calls INVOKE(&B::foo, a) where that is defined in [func.require] as:
Define INVOKE (f, t1, t2, ..., tN) as follows:
— (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;
— ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;
— ...
Your case fails to meet the conditions of the first bullet, because a is not an object of class B, nor a reference to a B or a class derived from B, so the second bullet applies and so it's equivalent to ((*a).*f)() which isn't valid.
It's defined this way to allow smart pointers to be used, e.g.
auto foo1 = std::mem_fn(B::foo);
auto p = std::make_shared<B>();
foo1(p);
The definition of INVOKE (which is also used by bind, function, async and other parts of the library that create call wrappers) means that when invoking a wrapped pointer-to-member, if the first argument t1 isn't a T then it is assumed to be some kind of pointer and gets dereferenced. This means it works with std::shared_ptr and std::unique_ptr but also with types that std::mem_fn knows nothing about, such as boost::shared_ptr and MyVeryOwnSmartPtr.
To make your code work it would be possible to add extra cases to handle when t1 is not a T or a type derived from T, but is_convertible<T>::value is true, and to invoke T(t1).*f)(), but that would complicate the specification and might have undesirable consequences in some cases.
Your "wrapper" will force the implicit conversion of its argument, but it can't handle smart pointers or rvalues of type B, which are both supported by mem_fn. If you have a specific case where you want to convert A objects to B to call the function, then just do that, the generic mem_fn template isn't suitable, but it is more flexible and generic and works in plenty of other situations.
(N.B. the definition of INVOKE is actually defective because it dereferences std::reference_wrapper objects in the same way as it dereferences your a argument. I've proposed a fix at http://cplusplus.github.com/LWG/lwg-active.html#2219, but that doesn't affect your example.)