C ++重载和模板化函子及其参数的完美转发

时间:2018-08-30 04:53:15

标签: c++ c++11 templates variadic-templates perfect-forwarding

假设我们有一个看起来像这样的函数

template <typename F, typename... A>
inline void execute(F&& functor, A&& ... args) {
    std::forward<decltype(functor)>(functor)(std::forward<decltype(args)>(args)...);
}

这适用于简单的非模板函数。但是,我正在尝试完善一种模板函数(一种非常人为设计的函数):

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>>;

尝试转发以上内容:

std::string buf("hello world");
execute(base64_rfc4648::encode, buf.c_str(), buf.size());

不起作用。模板推导失败:

  

注意:无法推断出模板参数“ F”

它还指出:

  

没有匹配功能可调用'execute(<unresolved overloaded function type>, const char*, std::__cxx11::basic_string<char>::size_type)'

我该如何解决?

注意:为了便于阅读,我在上面保留了简短信息,但是如果需要更多信息,可以添加。

2 个答案:

答案 0 :(得分:2)

我创建了一个MCVE来解决该问题,而不是代码。

因此,让我们有一个名为print()的通用函数,我们希望将该函数发送到您的execute()

template <typename Arg>
inline void print(Arg const & a) {
    std::cout << a << std::endl;
}

其中execute()是:

template <typename F, typename... A>
inline void execute(F&& functor, A&& ... args) {
    std::forward<decltype(functor)>(functor)(std::forward<decltype(args)>(args)...);
}

当我们尝试呼叫execute(print, 10)时失败。
问题在于execute()函数无法理解我们要调用print的哪个超载

现在可以通过2种方法解决此问题:

第一种方法,指定模板化函数的完整类型:

execute(print<int>, 10);

第二种方法,创建一个辅助函数。
每个问题都可以通过增加一层来解决
在将其传递给execute()

之前,此辅助函数将帮助我们推断类型。
template <typename Arg>
inline void execute_print(Arg const & a) {
    execute(print<Arg>, a); // we need to specify which overload to be invoked
}

然后您可以致电:execute_print(20);

以下是完整的工作代码供您参考(使用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;
}

答案 1 :(得分:1)

您可以简单地使用boost::hofbase64_rfc4648::encode包装在函数对象中。 execute(BOOST_HOF_LIFT(base64_rfc4648::encode), buf.c_str(), buf.size());

这是BOOST_HOF_LIFT的文档