【问题标题】:Address of an overloaded C++ template function involving SFINAE涉及 SFINAE 的重载 C++ 模板函数的地址
【发布时间】:2019-06-04 05:04:23
【问题描述】:

我需要获取涉及 SFINAE 的重载模板函数的地址。这种情况的一个很好的例子是 boost::asio::spawn found here...

https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/spawn.html

我如何找到这个特定实例的地址...

template<
    typename Function,
    typename Executor>
void spawn(
    const Executor & ex,
    Function && function,
    const boost::coroutines::attributes & attributes = boost::coroutines::attributes(),
    typename enable_if< is_executor< Executor >::value >::type* = 0);

我试过这个没有成功...

using Exec = boost::asio::io_context;
using Func = std::function<void(boost::asio::yield_context)>;
void (*addr)(Exec, Func) = boost::asio::spawn;

【问题讨论】:

  • 使用 static_cast。
  • 该函数接受 四个 参数。你不能将它的地址分配给一个指向函数的指针,因为它不是这样的。这与模板无关。尝试使用带有默认参数的普通函数。

标签: c++ templates sfinae


【解决方案1】:

boost::asio::spawn 不是函数。它是一个函数模板。这是一个可以创建功能的蓝图。无法获得指向函数模板的指针,因为它是一个纯粹的编译时构造。

boost::asio::spawn&lt;Func, Exec&gt; 是一个函数重载集,但它没有与签名void(Exec,Func) 匹配的重载。请记住,默认函数参数只是语法糖。这些参数仍然是函数签名的一部分。

这两个问题使得获取指向boost::asio::spawn 的指针变得困难而丑陋。使用 lambda 会容易得多。 lambda 将让您保留类型推导并利用默认参数:

auto func = [](auto&& exec, auto&& func) {
    boost::asio::spawn(std::froward<decltype(exec)>(exec),
                       std::forward<decltype(func)>(func));
};

即使你绝对需要一个函数指针,lambda 仍然可能是要走的路。你失去了参数类型推导,但仍然可以利用函数的默认参数:

void(*addr)(const Exec&, Func) = [](const Exec& exec, Func func) {
    boost::asio::spawn(exec, std::move(func));
};

这是可行的,因为无捕获的 lambda 可以转换为原始函数指针。

如果您出于某种原因确实、绝对需要一个直接指向 spawn 实例之一的指针,您可以得到它,但它并不漂亮:

using Exec = boost::asio::io_context::executor_type;
using Func = std::function<void(boost::asio::yield_context)>;

void(*addr)(const Exec&, Func&, const boost::coroutines::attributes&, void*) = boost::asio::spawn<Func&, Exec>;

但这样做你会失去很多。你不仅失去了参数类型推导和默认参数,你也失去了将左值和右值传递给函数的能力,因为你不再有一个推断的上下文来转发引用以工作。我必须得到一个指向接受对函数的左值引用的实例化。如果您希望它接受右值引用,请使用

void(*addr)(const Exec&, Func&&, const boost::coroutines::attributes&, void*) = boost::asio::spawn<Func, Exec>;

还要注意这个函数有四个参数。调用它,即

addr(my_io_context.get_executor(), my_function, boost::coroutines::attributes{}, nullptr);

Example

【讨论】:

  • “硬而丑陋”的方式是什么?需要实际函数地址是有原因的,这里我就不赘述了
  • @user1715664 已添加。我告诉过你它不漂亮。
【解决方案2】:

试图将此解决方案作为一个编辑放在问题中它会立即可见的地方,但版主似乎认为最好强迫读者到这里...

using Exec = boost::asio::io_context;
using Func = std::function<void(boost::asio::yield_context)>;
using Attr = boost::coroutines::attributes;

void (*addr)(const Exec&,
             Func&&,
             const Attr&,
             typename enable_if< is_executor< Executor >::value>::type*
            ) = boost::asio::spawn<Func, Exec>;

是的,很丑,但也不算太糟糕。

【讨论】:

  • 顺便说一句,我从问题中删除了您的答案,而且我不是版主。只是社区的普通成员。我们喜欢在这里保持整洁,答案属于答案,而不是问题本身。如果你想了解更多,我建议this meta question and its answers
猜你喜欢
  • 2015-05-29
  • 2018-08-16
  • 1970-01-01
  • 2017-12-22
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
  • 2015-09-17
  • 1970-01-01
相关资源
最近更新 更多