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.
Related
I'm trying to create a parameter pack full of function pointers, but GCC (with c++17 standard) generates a deduction failed error. Why is that?
As written here:
For pointers to functions, the valid arguments are pointers to functions with linkage (or constant expressions that evaluate to null pointer values).
In my example, that's the case (isn't it?).
Is this rule invalidated for parameter packs? Did I miss something in the standard? If that's the case, how can I fix my code, without passing the function pointers as function arguments (ie without declaring T run2(T input, Funcs... funcs).
// In f.hpp
template<typename T>
T run2(T input)
{
return input;
}
template<typename T, T(*f)(T), class ... Funcs>
T run2(T input)
{
return run2<T, Funcs...>(f(input));
}
// In m.cpp
unsigned add2(unsigned v)
{
return v+2;
}
int main()
{
unsigned a=1;
a = run2<unsigned, add2>(a); // works
a = run2<unsigned, add2, add2>(a); // doesn't work
std::cout << a << std::endl;
return 0;
}
This the error I get with run2<unsigned, add2, add2> (GCC doesn't tell me why the last attempt actually failed):
m.cpp: In function ‘int main()’:
m.cpp:37:37: error: no matching function for call to ‘run2(unsigned int&)’
a = run2<unsigned, add2, add2>(a);
^
In file included from m.cpp:2:0:
./f.hpp:85:3: note: candidate: template<class T> T run2(T)
T run2(T input)
^
./f.hpp:85:3: note: template argument deduction/substitution failed:
m.cpp:37:37: error: wrong number of template arguments (3, should be 1)
a = run2<unsigned, add2, add2>(a);
^
In file included from m.cpp:2:0:
./f.hpp:109:3: note: candidate: template<class T, T (* f)(T), class ... Funcs> T run2(T)
T run2(T input)
^
./f.hpp:109:3: note: template argument deduction/substitution failed:
You declared a type parameter pack, class... Funcs. You can't pass function pointers as arguments for type parameters, because they are values, not types. Instead, you need to declare the run2 template so that it has a function pointer template parameter pack. The syntax to do so is as follows:
template<typename T, T(*f)(T), T(*...fs)(T)>
T run2(T input)
{
return run2<T, fs...>(f(input));
}
(The rule is that the ... is part of the declarator-id and goes right before the identifier, namely fs.)
The pack fs can accept one or more function pointers of type T (*)(T).
I wanted to implement a overload for operator<< that allowed me to call a given function and output the result.
I therefore wrote an overload, but the conversion to bool is selected and when writing a function myself, it would not compile.
EDIT: Know that I do not want to call the lambda,
but instead pass it to the function where it should be called with a default constructed parameter list.
I have appended my code:
#include <iostream>
template<typename T>
void test(T *) {
std::cout << "ptr" << std::endl;
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
template<typename Ret, typename ...Args>
void test(Ret(*el)(Args...)) {
std::cout << "function ptr\n" << el(Args()...) << std::endl;
}
template<typename Char_T, typename Char_Traits, typename Ret, typename ...Args>
std::basic_ostream<Char_T, Char_Traits>& operator<<(
std::basic_ostream<Char_T, Char_Traits> &str, Ret(*el)(Args...)) {
return str << el(Args()...);
}
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test([]{return 5;}); // will not compile
}
I use gcc 7.3.1 with the version flag -std=c++14.
EDIT: Error message:
main.cc: In function ‘int main()’:
main.cc:25:23: error: no matching function for call to ‘test(main()::<lambda()>)’
test([]{return 5;});
^
main.cc:5:6: note: candidate: template<class T> void test(T*)
void test(T *) {
^~~~
main.cc:5:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘T*’ and ‘main()::<lambda()>’
test([]{return 5;});
^
main.cc:9:6: note: candidate: template<class T> void test(bool)
void test(bool) {
^~~~
main.cc:9:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: couldn't deduce template parameter ‘T’
test([]{return 5;});
^
main.cc:13:6: note: candidate: template<class Ret, class ... Args> void test(Ret (*)(Args ...))
void test(Ret(*el)(Args...)) {
^~~~
main.cc:13:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘Ret (*)(Args ...)’ and ‘main()::<lambda()>’
test([]{return 5;});
Your problem here is that Template Argument Deduction is only done on the actual argument passed to test. It's not done on all possible types that the argument could possibly converted to. That might be an infinite set, so that's clearly a no-go.
So, Template Argument Deduction is done on the actual lambda object, which has an unspeakable class type. So the deduction for test(T*) fails as the lambda object is not a pointer. T can't be deduced from test(bool), obviously. Finally, the deduction fails for test(Ret(*el)(Args...)) as the lambda object is not a pointer-to-function either.
There are a few options. You might not even need a template, you could accept a std::function<void(void)> and rely on the fact that it has a templated constructor. Or you could just take a test(T t) argument and call it as t(). T will now deduce to the actual lambda type. The most fancy solution is probably using std::invoke, and accepting a template vararg list.
Even though non-capturing lambdas have an implicit conversion to function pointers, function templates must match exactly for deduction to succeed, no conversions will be performed.
Therefore the easiest fix is to force the conversion with a +
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test(+[]{return 5;});
// ^
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
Template is not needed. In fact you overload functions, not templates. Replace it with
void test(bool) {
std::cout << "bool" << std::endl;
}
Now your sample will compile.
Given the following source code:
#include <memory>
#include <iostream>
using namespace std;
struct concept
{
virtual void perform() = 0;
};
struct model : concept, enable_shared_from_this<model>
{
void perform() override {
cout << "my pointer is " << shared_from_this().get() << endl;
}
};
int main(int argc, const char * argv[])
{
// shared_ptr<concept> concept_ptr = make_shared<model>();
shared_ptr<concept> concept_ptr { new model };
concept_ptr->perform();
return 0;
}
Compiling under gcc, this code compiles and associates the internal weak_ptr with the address of model.
Under clang the code will not compile (error message included at the end)
If you replace the initialisation of concept_ptr with shared_ptr<concept> concept_ptr = make_shared<model>(); it will compile on both.
Which is correct?
edit:
My version of clang is the one that ships with Xcode:
$ clang --version
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix
edit2:
Just wanted to say thanks to everyone for contributing.
If you're interested, the reason I want to do this is that I want an opaque interface to an implementation with shared-handle semantics. Some implementations (async ones) require that callback objects ensure that the implementation object still exists (argues for shared_from_this and weak_ptr::lock). Other implementations do not require this. I wanted to avoid encumbering the concept (public interface) with the enable_shared_from_this<> base class, since that couples implementation with interface - a known evil.
In most cases, it's reasonable to use make_shared to create the implementation object. In rarer cases that require a custom destructor, the following seems portable:
auto concept_ptr = static_pointer_cast<concept>(shared_ptr<model> {
new model ,
[](model* self) {
// some_deletion_operation on self;
} });
appendix:
error message on clang:
In file included from /Users/richardh/Documents/dev/Scratchpad/tryit/tryit/try2.cpp:1:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/memory:4013:35: error: no viable overloaded '='
__e->__weak_this_ = *this;
~~~~~~~~~~~~~~~~~ ^ ~~~~~
...etc...
I understand that libstdc++ follows the standard more closely here.
Concerning the requirements for
shared_ptr<T> shared_from_this();
shared_ptr<const T> shared_from_this() const;
both N3337 §20.7.2.4 (7) and N3936 §20.8.2.5 (7) only require
enable_shared_from_this<T> shall be an accessible base class
of T. *this shall be a subobject of an object t of type T. There shall
be at least one shared_ptr instance p that owns &t.
There is no requirement named that one shared_ptr owning &t actually has to be a shared_ptr<T> or shared_ptr<A_to_T_Convertible>.
And that very function is the core of that class' functionality.
Thus, given Tp as the actual param of the enabled_shared_from_this and Tp1 as the actual parameter of that owning shared_ptr, is_convertible<Tp1, Tp>::value == true, let alone is_same<Tp1, Tp>::value == true, is not required by the standard, same for respective pointers.
And indeed, the full output of clang++ using libc++ has
/usr/local/bin/../include/c++/v1/memory:3997:35: error: no viable overloaded '='
__e->__weak_this_ = *this;
~~~~~~~~~~~~~~~~~ ^ ~~~~~
/usr/local/bin/../include/c++/v1/memory:4035:5: note: in instantiation of
function template specialization
'std::__1::shared_ptr<concept>::__enable_weak_this<model>' requested here
__enable_weak_this(__p);
^
[...]enable_shared.cxx:34:25: note: in instantiation
of function template specialization
'std::__1::shared_ptr<concept>::shared_ptr<model>' requested here
shared_ptr<concept> model_ptr1(new model);
^
/usr/local/bin/../include/c++/v1/memory:4942:15: note: candidate function not
viable: no known conversion from 'std::__1::shared_ptr<concept>' to 'const
std::__1::weak_ptr<model>' for 1st argument
weak_ptr& operator=(weak_ptr const& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4953:15: note: candidate function not
viable: no known conversion from 'std::__1::shared_ptr<concept>' to
'std::__1::weak_ptr<model>' for 1st argument
weak_ptr& operator=(weak_ptr&& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4949:9: note: candidate template
ignored: could not match 'weak_ptr' against 'shared_ptr'
operator=(weak_ptr<_Yp> const& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4960:9: note: candidate template
ignored: could not match 'weak_ptr' against 'shared_ptr'
operator=(weak_ptr<_Yp>&& __r) _NOEXCEPT;
^
/usr/local/bin/../include/c++/v1/memory:4967:13: note: candidate template
ignored: disabled by 'enable_if' [with _Yp = concept]
is_convertible<_Yp*, element_type*>::value,
^
So libc++ here wants
is_convertible<Tp1* /*= Base* = concept**/, Tp* /*= Derived* = model* */>
which of course fails here, that the run-time *this of that very shared_ptr<Tp1> would be dynamic_cast-able to Tp* is out of ansatz here.
From this perspective, it's also clear why shared_ptr<concept> concept_ptr = make_shared<model>(); doesn't suffer from that; on the rhs there is a shared_ptr<Tp /* = derived = model */> constructor and for that ptr is_convertible holds.
libstdc++ doesn't suffer from this, because it passes the argument, thus its type (= Derived = model), of the shared_ptr<Tp1 /* = Base = concept*/> constructor down to the internal weak_ptr<T /*= Derived = model*/> assignment, not the shared_ptr in construction.
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L848
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
{
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L858
template<typename _Tp1>
explicit __shared_ptr(_Tp1* __p)
: _M_ptr(__p), _M_refcount(__p)
{
__glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
static_assert( !is_void<_Tp1>::value, "incomplete type" );
static_assert( sizeof(_Tp1) > 0, "incomplete type" );
__enable_shared_from_this_helper(_M_refcount, __p, __p);
}
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L1459
template<typename _Tp, _Lock_policy _Lp>
class __enable_shared_from_this
{
https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/include/bits/shared_ptr_base.h#L1482
private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }
template<typename _Tp1>
friend void
__enable_shared_from_this_helper(const __shared_count<_Lp>& __pn,
const __enable_shared_from_this* __pe,
const _Tp1* __px) noexcept
{
if (__pe != 0)
__pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
}
My point of view only; comments welcome.
#Richard Hodges: +1, very interesting topic
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
Consider the following typical SFINAE test function (it checks if a type has a begin() member function)
template <class> constexpr bool
has_begin_member (...) { return false; }
template <class T> constexpr bool
has_begin_member (decltype (std::declval <T>().begin ())* = 0) {
return true;
}
I can call it with an argument:
has_begin_member <int> (0); // yields false
but without any arguments:
has_begin_member <int> (); // compilation error
it leads to the following ambiguity:
error: call of overloaded 'has_begin_member()' is ambiguous
note: candidates are:
note: constexpr bool has_begin_member(...)
note: constexpr bool has_begin_member(decltype (declval<T>().begin())*)
Why doesn't the "ellipsis trick" work in that case?
Edit: full program:
#include <utility>
#include <vector>
template <class> constexpr bool
has_begin_member (...) { return false; }
template <class T> constexpr bool
has_begin_member (decltype (std::declval <T>().begin ())* = 0) {
return true;
}
static_assert (!has_begin_member <int> (0), "broken");
static_assert (has_begin_member <std::vector <int>> (0), "broken");
static_assert (!has_begin_member <int> (), "broken");
static_assert (has_begin_member <std::vector <int>> (), "broken");
int
main (){}
Compilation:
g++ -std=c++11 -o toto ./toto.cpp
./toto.cpp:17:58: error: call of overloaded 'has_begin_member()' is ambiguous
./toto.cpp:17:58: note: candidates are:
./toto.cpp:5:5: note: constexpr bool has_begin_member(...) [with <template-parameter-1-1> = std::vector<int>]
./toto.cpp:8:5: note: constexpr bool has_begin_member(decltype (declval<T>().begin())*) [with T = std::vector<int>; decltype (declval<T>().begin()) = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]
For the has_begin_member<int>() case the second overload is not viable because template argument substitution fails, so only the first overload is viable, so no ambiguity.
For the has_begin_member<std::vector<int>>() case substitution succeeds so there are two viable functions.
13.3.2 [over.match.viable]:
If there are m arguments in the list, all candidate functions having exactly m parameters are viable.
A candidate function having fewer than m parameters is viable only if it has an ellipsis in its parameter
list (8.3.5). For the purposes of overload resolution, any argument for which there is no corresponding
parameter is considered to “match the ellipsis” (13.3.3.1.3) .
A candidate function having more than m parameters is viable only if the (m+1)-st parameter has a
default argument (8.3.6). For the purposes of overload resolution, the parameter list is truncated
on the right, so that there are exactly m parameters.
In this case m is zero, the first overload is viable (by the second bullet) and the second overload is also viable (by the third bullet) but for the purposes of overload resolution the parameter with a default argument is ignored, and so the best viable functions is found by comparing:
template<> constexpr bool has_begin_member<vector<int>>(...);
template<> constexpr bool has_begin_member<vector<int>>();
Which is obviously ambiguous, just like this is:
int f(...);
int f();
int i = f(); // error
There is no conversion sequence needed to call either function, so they cannot be ranked in terms of which has a "better conversion sequence" than the other (using the rules in 13.3.3.2 [over.ics.rank],) which means they are ambiguous.