Reputation: 3968
Suppose we have a function that looks like:
template <typename F, typename... A>
inline void execute(F&& functor, A&& ... args) {
std::forward<decltype(functor)>(functor)(std::forward<decltype(args)>(args)...);
}
This works for simple non-templated functions. However, I am trying to perfect-forward a templated function(a quite contrived one):
namespace detail {
template <typename CodecImpl>
class codec
{
public:
//
// Encoding
// Convenient version, returns an std::string.
static std::string encode(const uint8_t* binary, size_t binary_size);
static std::string encode(const char* binary, size_t binary_size);
...
};
class base64_rfc4648
{
public:
template <typename Codec> using codec_impl = stream_codec<Codec, base64_rfc4648>;
static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() {
static_assert(sizeof(base64_rfc4648_alphabet) == 64, "base64 alphabet must have 64 values");
return sizeof(base64_rfc4648_alphabet);
}
static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx)
{
return base64_rfc4648_alphabet[idx];
}
...
};
} // namespace detail
using base64_rfc4648 = detail::codec<detail::base64<detail::base64_rfc4648>>;
Trying to forward the above:
std::string buf("hello world");
execute(base64_rfc4648::encode, buf.c_str(), buf.size());
Does not work. Template deduction fails:
note: couldn't deduce template parameter 'F'
and it also notes:
No matching function for call to
'execute(<unresolved overloaded function type>, const char*, std::__cxx11::basic_string<char>::size_type)'
How can I fix this?
NOTE: I kept the information short above for readability, but if more info is needed I can add.
Upvotes: 3
Views: 325
Reputation: 598
You can simply use boost::hof
to wrap base64_rfc4648::encode
in a function object.
execute(BOOST_HOF_LIFT(base64_rfc4648::encode), buf.c_str(), buf.size());
Here is the doc of BOOST_HOF_LIFT
Upvotes: 1
Reputation: 870
I have created a MCVE to work on the problem, rather than the code.
So let us have a generic function called print()
which we want to send to your execute()
template <typename Arg>
inline void print(Arg const & a) {
std::cout << a << std::endl;
}
where execute()
is:
template <typename F, typename... A>
inline void execute(F&& functor, A&& ... args) {
std::forward<decltype(functor)>(functor)(std::forward<decltype(args)>(args)...);
}
When we try to call execute(print, 10)
it fails.
The problem is that the execute()
function doesn't understand which overload of print
are we trying to call.
Now this problem can be solved in 2 ways :
First approach, specify the complete type of the templated function :
execute(print<int>, 10);
Second approach, create a helper function.
Every problem can be solved by adding one more layer.
This helper function will help us deduce the types, before we pass it to execute()
template <typename Arg>
inline void execute_print(Arg const & a) {
execute(print<Arg>, a); // we need to specify which overload to be invoked
}
And then you can call : execute_print(20);
Here is a full working code for your reference(compiled using C++11):
#include <string>
#include <iostream>
template <typename Arg>
inline void print(Arg const & a) {
std::cout << a << std::endl;
}
template <typename F, typename... A>
inline void execute(F&& functor, A&& ... args) {
std::forward<decltype(functor)>(functor)(std::forward<decltype(args)>(args)...);
}
template <typename Arg>
inline void execute_print(Arg const & a) {
execute(print<Arg>, a); // we need to specify which overload to be invoked
}
int main() {
// execute(print, 5); // wont compile
execute(print<int>, 10);
execute_print(20);
return 0;
}
Upvotes: 2