【问题标题】:Perfect forwarding of C++ overloaded and templated functors and its argumentsC++ 重载和模板化仿函数及其参数的完美转发
【发布时间】:2019-02-04 22:48:36
【问题描述】:

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

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(&lt;unresolved overloaded function type&gt;, const char*, std::__cxx11::basic_string&lt;char&gt;::size_type)'

我该如何解决这个问题?

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

【问题讨论】:

  • 本质上是相同的问题,除了使用模板而不是重载函数:stackoverflow.com/questions/43171323/…
  • 如果 C++ 14 是一个选项,那么接受的答案应该适合你。
  • 这与转发无关。您正在尝试传入重载函数。那行不通,使用 lambda 或编写仿函数。
  • 我明白了。我现在正在使用 lambda。谢谢
  • decltype(args) 而不是 A 是怎么回事?

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


【解决方案1】:

我创建了一个 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 中的哪个重载

现在这个问题可以通过两种方式解决:

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

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

【讨论】:

  • 我喜欢这个答案,但我应该指定还有更多我想通过execute 调用的函数。这意味着我需要execute_fooexecute_bar 等。不过,我仍然支持你的答案:)
  • 同意。我也希望使它更通用,但没有这样做。因此,我只发布了正常工作的内容。当我想将我的函数传递给更高阶的函数retry(Func &amp;&amp; func, Args &amp;&amp; ... args) 时,我曾经遇到过这个问题。因为我只有几个函数,所以我为它们编写了辅助函数。
【解决方案2】:

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

这是BOOST_HOF_LIFT的文档

【讨论】:

  • 谢谢,这正是我需要的
  • 我不确定这是否适用于 C++11。不过,它将在 C++14 之后编译。
猜你喜欢
  • 1970-01-01
  • 2011-09-23
  • 2016-07-22
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多