包含SFINAE的C ++模板函数的重载地址

时间:2019-06-04 05:04:23

标签: c++ templates sfinae

我需要获取涉及SFINAE的重载模板函数的地址。一个很好的例子就是在这里找到boost :: asio :: spawn ...

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;

2 个答案:

答案 0 :(得分:4)

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

boost::asio::spawn<Func, Exec>是一个函数重载集,但没有与签名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

答案 1 :(得分:0)

试图将这种解决方案作为编辑,以便立即解决该问题,但主持人似乎认为最好将读者带到此处...

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

是的,很丑但是还算不错。