【问题标题】:C++ template function pointer type deductionC++模板函数指针类型推导
【发布时间】:2021-06-22 20:25:41
【问题描述】:

我有以下代码

using my_map_t = std::map<int, Object<double>>;
using my_map_iterator_t = my_map_t::iterator;


template <typename FWD, typename Func>
void inner(my_map_t& map, int key, FWD&& obj, Func emplacer) {
        emplacer(map, key, std::forward<FWD>(obj));
}
  

my_map_t map;

template <typename FWD>
void outer(my_map_t& map, int key, FWD&& obj)
{
        auto lambda = [](my_map_t& m, int k, FWD&& o) {
                m.emplace(k, std::forward<FWD>(o));
        };

        inner(map, key, std::forward<FWD>(obj), lambda);
}

编译无痛。所以这意味着他自动推导出inner函数的模板参数。 但是,如果我引入一个函数指针我需要指定函数指针模板参数,否则编译器会抱怨

using my_map_t = std::map<int, Object<double>>;
using my_map_iterator_t = my_map_t::iterator;


template <typename FWD, typename Func>
void inner(my_map_t& map, int key, FWD&& obj, Func emplacer) {
        emplacer(map, key, std::forward<FWD>(obj));
}

template <typename FWD, typename Func>
void(*fp)(my_map_t&, int, FWD&&, Func) = &inner;


my_map_t map;

template <typename FWD>
void outer(my_map_t& map, int key, FWD&& obj)
{
        auto lambda = [](my_map_t& m, int k, FWD&& o) {
                m.emplace(k, std::forward<FWD>(o));
        };

        (*fp<FWD, decltype(lambda)>)(map, key, std::forward<FWD>(obj), lambda);
}

为什么在函数指针的情况下,参数推导不再起作用? 我犯了什么错误吗?有没有办法获得更好的语法?

添加注释

我需要使用函数指针,因为我有一些与inner 签名相同的函数。让我们称他们为inner1inner2inner3。它们被一些外部函数调用

void outer(...) {
     if(...) {

         inner1(...)
     } else if (...) {
     
         inner2(...)
     } else {

         inner3(...)
     }
     some_long_task(...)
}

现在在我的例子中,outer 函数被循环调用。 ifs 中的检查可能很耗时,并且它们独立于 outer 函数的参数。在执行some_long_task 时,我在想,利用一些cpu 并行性设置一个指向right 函数inner1inner2inner3 的函数指针,这样,新的循环开始了,我不必浪费时间进行 if 检查。

【问题讨论】:

  • 我有点困惑。不使用变量模板是否可以达到相同的结果(我发现它们是在 c++14 中引入的,我必须达到 C++11)?
  • 为什么你需要fp作为函数指针?为什么不是 lambda?从 C++14 开始,您可以将 fp 定义为 [](my_map_t&amp; map, int key, auto&amp;&amp; obj, auto func){ inner(map, key, std::forward&lt;decltype(obj)&gt;(obj), func); },或者在 C++11 中定义一个与此 lambda 相同的 functor
  • 我的意思是,我必须在函数内部定义函子(因为我使用 c++11)。有可能吗?
  • 没有。类似于this question 和现在的其他人,你希望一些仿函数有一个模板接口,但是是一个单一的类型。这是不可能的,除非在未来的 C++ 中有虚拟函数模板
  • 您的“函数指针”的问题是您无法真正捕获额外的数据(您当前传递 lambda)。 std::function&lt;void(my_map_t&amp;, int)&gt; 可能是您想要的,而不是函数指针。

标签: c++ c++11 templates lambda type-deduction


【解决方案1】:
template <typename FWD, typename Func>
void(*fp)(my_map_t&, int, FWD&&, Func) = &inner;

不是普通的函数指针。这就是所谓的variable template。当你有一个变量模板时,为了引用一个特定的实例,你必须指定模板参数。为了证明这一点,请考虑

template <typename T>
constexpr T pi = T(3.1415926535897932385L);  

您不能只使用cout &lt;&lt; pi,因为我们不知道使用哪个pi。同样的情况发生在

(*fp<FWD, decltype(lambda)>)(map, key, std::forward<FWD>(obj), lambda);

这里fp 需要&lt;FWD, decltype(lambda)&gt;,因此编译器可以知道要引用哪个特定的fp 实例。它甚至在评估函数调用之前就必须这样做,因为它需要根据函数检查参数。

我们不需要指定参数的是像 CTAD 这样的未来,但适用于函数指针变量 temapltes。

【讨论】:

  • 我明白了,非常感谢。顺便说一句,有没有办法避免使用变量模板?我正在考虑使用模板类重载operator(),然后使用void 指针,但也许这不是一个好主意。我问这个是因为我意识到我必须达到 c++11 并且模板变量是在 c++14 中引入的。
  • @MaPo 为什么你不能使用第一个有效的例子?您能否向您的问题添加您想要工作的代码示例,但没有?我不明白你为什么需要函数指针。
猜你喜欢
  • 2016-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
相关资源
最近更新 更多