I have a piece of code which, simplified a bit, amounts to the following which compiles and works correctly.
template <typename Interface, typename... Args>
struct factory_function {
typedef function<shared_ptr<Interface> (Args...)> type;
};
template <typename Interface, typename Implementer, typename... Args>
shared_ptr<Interface> create_function(Args... args) {
return make_shared<Implementer>(args...);
}
template <typename Interface, typename... Args>
int register_factory(identifier id, typename factory_function<Interface, Args...>::type factory) {
}
int main(int argc, char *argv[]) {
register_factory<Iface>(1000, create_function<Iface, Impl>);
return 0;
}
But when trying to use the newer using ... =
construct instead of a typedef in a struct like this:
template <typename Interface, typename... Args>
using factory_function = function<shared_ptr<Interface> (Args...)>;
and then change typename factory_function<Interface, Args...>::type
into factory_function<Interface, Args...>
, I get a compile error:
foo.cc: In function ‘int main(int, char**)’:
foo.cc:31:61: error: no matching function for call to ‘register_factory(int, <unresolved overloaded function type>)’
register_factory<Iface>(1000, create_function<Iface, Impl>);
^
foo.cc:31:61: note: candidate is:
foo.cc:17:5: note: template<class Interface, class ... Args> int register_factory(identifier, factory_function<Interface, Args ...>)
int register_factory(identifier id, factory_function<Interface, Args...> factory) {
^
foo.cc:17:5: note: template argument deduction/substitution failed:
foo.cc:31:61: note: mismatched types ‘std::function<std::shared_ptr<Iface>(Args ...)>’ and ‘std::shared_ptr<Iface> (*)()’
register_factory<Iface>(1000, create_function<Iface, Impl>);
^
foo.cc:31:61: note: could not resolve address from overloaded function ‘create_function<Iface, Impl>’
UPDATE:
This is the full, compilable test case, compiled with g++ -std=c++11 foo.cc
:
#include <functional>
#include <memory>
using namespace std;
typedef int identifier;
template <typename Interface, typename... Args>
struct factory_function {
typedef function<shared_ptr<Interface> (Args...)> type;
};
//template <typename Interface, typename... Args>
//using factory_function = function<shared_ptr<Interface> (Args...)>;
template <typename Interface, typename Implementer, typename... Args>
shared_ptr<Interface> create_function(Args... args) {
return make_shared<Implementer>(args...);
}
template <typename Interface, typename... Args>
int register_factory(identifier id, typename factory_function<Interface, Args...>::type factory) {
//int register_factory(identifier id, factory_function<Interface, Args...> factory) {
}
class Iface {
public:
virtual void foo() = 0;
};
class Impl : public Iface {
public:
virtual void foo() {}
};
int main(int argc, char *argv[]) {
register_factory<Iface>(1000, create_function<Iface, Impl>);
return 0;
}
The commented lines show what is not working.
With int register_factory(identifier id, typename factory_function<Interface, Args...>::type factory)
, compiler cannot deduce type Interface
and Args
, so the call to register_factory<Iface>(1000, create_function<Iface, Impl>);
is explicitly int register_factory(identifier id, typename factory_function<Interface>::type);
With the alternative definition (with using) int register_factory(identifier id, factory_function<Interface, Args...>
, compiler have to try to deduce Args
(Interface
is explicitly set to Iface
) but unfortunately, a conversion is needed and compiler failed (std::shared_ptr<Iface> (*)()
is not an exact match for any function<std::shared_ptr<Iface>(Args...)>
)
A workaround is your second solution is to force the type of create_function<Iface, Impl>
to a std::function
. the following may help so:
template <typename R, typename...Args>
std::function<R(Args...)> make_function(R (*f)(Args...))
{
return f;
}
And later:
register_factory<Iface>(1000, make_function(create_function<Iface, Impl>));
You can make it work by combining the two approaches ;)
template <typename Interface, typename... Args>
struct fa_fu_helper {
typedef function<shared_ptr<Interface> (Args...)> type;
};
template <typename Interface, typename... Args>
using factory_function = typename fa_fu_helper<Interface, Args...>::type;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With