Trying to pass a lambda to a constructor:
#include <functional>
#include <exception>
template<typename R>
class Nisse
{
private:
Nisse(Nisse const&) = delete;
Nisse(Nisse&&) = delete;
Nisse& operator=(Nisse const&) = delete;
Nisse& operator=(Nisse&&) = delete;
public:
Nisse(std::function<R> const& func) {}
};
int main()
{
Nisse<int> nisse([](){return 5;});
}
When I compile I get an error message:
Test.cpp: In function ‘int main()’:
Test.cpp:19:39: error: no matching function for call to ‘Nisse<int>::Nisse(main()::<lambda()>)’
Test.cpp:19:39: note: candidate is:
Test.cpp:14:9: note: Nisse<R>::Nisse(const std::function<R>&) [with R = int]
Test.cpp:14:9: note: no known conversion for argument 1 from ‘main()::<lambda()>’ to ‘const std::function<int>&’
The type of the template arg to std::function is wrong. Try using
Nisse(std::function<R()> const& func) {}
Specifically, the template argument needs to be a function type, but all you were passing was the desired return type.
Related
I want to use Boost phoenix member function operator for the class function that has overloads, like here.
The following example fails:
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/operator.hpp>
using namespace std;
using namespace boost::phoenix::placeholders;
struct A
{
int m_id = 1;
int func() const { return 1; }
void func(int id) { m_id = id; }
};
int main()
{
A *a = new A;
auto retVal = (arg1->*&A::func)()(a);
return 0;
}
With error:
In function 'int main()': 17:21: error: no match for 'operator->*'
(operand types are 'const type {aka const
boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::
tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0l>
>}' and '<unresolved overloaded function type>') 17:21: note: candidate is: In
file included from /usr/include/boost/phoenix/operator/arithmetic.hpp:13:0,
from /usr/include/boost/phoenix/operator.hpp:13, from /usr/include/boost
/phoenix/phoenix.hpp:13, from 1: /usr/include/boost/proto/operators.hpp:295:9:
note: template<class Left, class Right> const typename
boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain,
boost::proto::detail::not_a_grammar,
boost::mpl::or_<boost::proto::is_extension<Arg>,
boost::proto::is_extension<Right> >, boost::proto::tagns_::tag::mem_ptr, const
Left&, const Right&>::type boost::proto::exprns_::operator->*(Left&&,
Right&&) BOOST_PROTO_DEFINE_OPERATORS(is_extension, deduce_domain) ^
/usr/include/boost/proto/operators.hpp:295:9: note: template argument
deduction/substitution failed: 17:28: note: couldn't deduce template parameter
'Right'
However, if I comment the line void func(int id) { m_id = id; } out, it works as expected.
How can I tell which of the overloads to use?
Handling (member) function pointers to overload sets is always a pain. You need to cast the address to a pointer that has the exact signature of the desired overload. In your case, for selection int A::func():
auto retVal = (arg1->*static_cast<int (A::*)() const>(&A::func))()(a);
or a bit more readable, but basically the same:
const auto memFctPtr = static_cast<int (A::*)() const>(&A::func);
auto retVal = (arg1->*memFctPtr)()(a);
I'm trying to make a movable wrapper to non-copyable, non-movable class, however I have a problem passing a const std::string variable to the constructor. The minimal example below produces following error:
#include <iostream>
#include <memory>
#include <string>
#include <utility>
struct X {
std::string x;
X(const std::string &x) : x(x) {}
X(const X &x) = delete;
X(X &&x) = delete;
};
struct Wrapper {
std::unique_ptr<X> x;
Wrapper(const Wrapper & wrapper) = delete;
Wrapper(Wrapper && wrapper) = default;
template<typename... Args>
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
};
int main() {
const std::string XXX = "XXX";
Wrapper w{XXX};
std::cout << w.x->x << std::endl;
}
Error message here:
forwarding.cc:21:53: error: no matching function for call to 'forward'
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
^~~~~~~~~~~~
forwarding.cc:26:13: note: in instantiation of function template specialization 'Wrapper::Wrapper<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > &>' requested here
Wrapper w{XXX};
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:73:5: note: candidate template ignored: couldn't infer template argument '_Tp'
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:84:5: note: candidate template ignored: couldn't infer template argument '_Tp'
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
^
1 error generated.
You need to explicitly pass template parameters to std::forward:
std::forward<Args>(args)...
This is because std::forward needs some way of knowing the "original value category" of args..., which is impossible through template argument deduction alone as args is always an lvalue.
Lvalues will deduced as lvalue references in the context of template argument deduction for forwarding references (as a special rule), so std::forward can do its job by looking at the types inside Args....
I have this simplified code consisting of a class with a static function, which is stored in map:
#include <iostream>
#include <functional>
#include <map>
class A {
public:
static void f(const std::string &s) { std::cout << s; }
};
std::map<std::string, std::function<void(std::string const &)>> fs;
int main() {
fs["f"] = &A::f;
fs["f"]("hello");
}
This prints the expected hello.
The problem occurs if I overload f() with:
static void f(const std::string &s, int c) { while(c-->0) { std::cout << s; } }
This results in the error:
error: no viable overloaded '='
fs["f"] = &A::f;
~~~~~~~ ^ ~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2241:7: note: candidate function not viable: no overload of 'f' matching 'const std::function<void (const std::basic_string<char> &)>' for 1st argument
operator=(const function& __x)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2259:7: note: candidate function not viable: no overload of 'f' matching 'std::function<void (const std::basic_string<char> &)>' for 1st argument
operator=(function&& __x)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2273:7: note: candidate function not viable: no overload of 'f' matching 'nullptr_t' for 1st argument
operator=(nullptr_t)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2302:2: note: candidate template ignored: couldn't infer template argument '_Functor'
operator=(_Functor&& __f)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/functional:2311:2: note: candidate template ignored: couldn't infer template argument '_Functor'
operator=(reference_wrapper<_Functor> __f) noexcept
^
However, calling both functions works:
A::f("hello ");
A::f("echo ", 3);
So, my question are:
Why this code not compiling even though the operator= seems to exist and function if I don't overload f()?
How can I get it to work without giving both functions different names?
Why this code not compiling even though the operator= seems to exist
and function if I don't overload f()?
Because the compiler doesn't know which overload to choose. How could he? There is no criterion upon which he can decide which one is suited better. Every std::function allows arbitrary function objects to be assigned and doesn't check any signatures. If you wanted to save only function pointers of this particular signature you should have declared the map appropriately.
How can I get it to work without giving both functions different
names?
As already mentioned it works by casting the expression to a function pointer of the specific type.
fs["f"] = static_cast<void(*)(std::string const&)>( &A::f );
This way no ambiguities arise; There is exactly one overload that can be casted to this function to pointer type. If this appears more often then a typedef could be feasible.
Or a little helper class template:
template <typename... Exact>
struct funptr
{
template <typename R>
constexpr auto operator()(R(*p)(Exact...)) -> decltype(p)
{ return p; }
};
fs["f"] = funptr<std::string const&>()(&A::f);
Demo.
I am trying to store a forward function into std::function. If I use std::bind, I get error message like no viable conversion from .... If I use lambda, it compile okay.
Here is sample code
#include <functional>
template<typename Handler>void func1(int a, Handler&& handler) {}
template<typename Handler>void func2(Handler&& handler)
{
// this line compile fine
std::function<void ()> funcA = [handler = std::move(handler)]() { func1(1, std::move(handler)); };
// this line got compile error
std::function<void ()> funcB = std::bind(func1<Handler>, 1, std::move(handler));
}
int main()
{
func2(&main); // this just a sample, I am using functor as argument in real code
}
Trying both g++ --std=c++1y (v4.9.0) and clang++ --std=c++1y (v3.4.1) yield the same result
edit: clang++ error message
main.cpp:8:28: error: no viable conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int
(*&&)()), int, int (*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to
'std::function<void ()>'
std::function<void ()> funcB = std::bind(&func1<Handler>, 1, std::move(handler));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:14:5: note: in instantiation of function template specialization 'func2<int (*)()>' requested here
func2(&main);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2181:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2192:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'const std::function<void ()> &'
for 1st argument
function(const function& __x);
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2201:7: note: candidate constructor not viable: no
known conversion from 'typename _Bind_helper<__is_socketlike<void (*)(int, int (*&&)())>::value, void (*)(int, int (*&&)()), int, int
(*)()>::type' (aka '_Bind<__func_type (typename decay<int>::type, typename decay<int (*)()>::type)>') to 'std::function<void ()> &&' for
1st argument
function(function&& __x) : _Function_base()
^
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../include/c++/4.9.0/functional:2226:2: note: candidate template ignored:
substitution failure [with _Functor = std::_Bind<void (*(int, int (*)()))(int, int (*&&)())>]: no matching function for call to object of
type 'std::_Bind<void (*(int, int (*)()))(int, int (*&&)())>'
function(_Functor);
^
1 error generated.
INTRODUCTION
std::bind will try to call func1<Handler> with an lvalue-reference, but your instantiation of func1 will make it only accept rvalues.
EXPLANATION
Here we have reduced your testcase to the bare minimum to show what is going on, the snippet below is ill-formed and an explanation will follow to why that is.
#include <functional>
template<class T>
void foobar (T&& val);
int main() {
std::function<void()> f = std::bind (&foobar<int>, std::move (123));
}
In the above we will instantiate foobar with T = int, which makes the type of argument val to be an rvalue-reference to int (int&&).
std::move(123) will move-construct our value to be stored inside the object created by std::bind, but the Standard says that when std::bind later invokes the stored function, all arguments are passed as TiD cv &; ie. as lvalues.
This behavior is mandated by the Standard (n3797), as stated in section [func.bind.bind]p10.
By changing the previous ill-formed snippet into the following, no error will be raised, since foobar<int> now accepts an lvalue-reference; suitable to be bound to the lvalue passed to our function by the function-object returned by std::bind.
std::function<void()> f = std::bind (&foobar<int&>, std::move (123));
???
#include <functional>
#include <type_traits>
#include <iostream>
int main() {
auto is_lvalue = [](auto&& x) {
return std::is_lvalue_reference<decltype(x)> { };
};
auto check = std::bind (is_lvalue, std::move (123));
bool res = check (); // res = true
}
in short: function has to be copyable. bind with rvalue returns non-copyable object. Workaround is to capture/bind with shared_ptr containing abovementioned value
I have a class template with template parameter T and a member of type T. I want to initialize that member with a parameter passed to the ctor and I also want the passed parameter to be moved if it's a rvalue reference and if T supports move semantic:
template <typename T>
class C {
public:
explicit C(T t) : t_(t)
{
}
explicit C(T&& t) : t_(std::move(t))
{
}
...
private:
T t_;
};
g++ 4.8 gives the following error if I try to pass rvalue reference to the ctor:
int main()
{
int x = 0;
C<int> p1{x}; // OK
C<int> p2{1}; // error g++-4.8: call of overloaded ‘C(<brace-enclosed initializer list>)’ is ambiguous
return 0;
}
The full error text:
g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
main.cpp: In function ‘int main()’:
main.cpp:23:16: error: call of overloaded ‘C()’ is ambiguous
C p2{1}; // error g++-4.8: call of overloaded ‘C()’ is ambiguous
^
main.cpp:23:16: note: candidates are:
main.cpp:12:11: note: C::C(T&&) [with T = int]
explicit C(T&& t) : t_(std::move(t))
^
main.cpp:8:14: note: C::C(T) [with T = int]
explicit C(T t) : t_(t)
^
main.cpp:6:7: note: constexpr C::C(const C&)
class C {
^
main.cpp:6:7: note: constexpr C::C(C&&)
Could someone help me, please?
Thanks!
I solved the problem by making the parameter t in C(T t) const reference.