传递 lambda 作为 std::function 的参数时,C++ 候选模板忽略错误

标签 c++ c++11 templates c++14 std-function

这是我在 C++ 中遇到的模板问题的一般框架版本。当从 foo 调用时,我不太明白如何让 bar 函数模板被识别为一个合理的候选者。

#include <iostream>
#include <cstdlib>
#include <unordered_map>

template<class T>
std::unordered_map<std::string, T> getStr2TMap() {
  return {}; // suppose logic here is a bit more involved
}

template<class T>
std::unordered_map<int, T> getInt2TMap() {
  return {}; // suppose logic here is a bit more involved
}

template<class U, class T>
void bar(
  const std::function<void (std::unordered_map<U, T>&&)>& baz
) {
  if (rand() % 2 > 0) {
    baz(getInt2TMap<T>());
  } else {
    baz(getStr2TMap<T>());
  }
}

template<class T>
void foo(
  const std::unordered_map<std::string, T>& map1
) {
  bar([&map1](auto&& map2) {
    // do some things with map1 and map2
  });
}

int main() {
  std::unordered_map<std::string, int> myMap;
  foo<int>(myMap);
}

编辑

代码的简化版,同样的错误。不过,我正在寻找上述版本的解决方案,而不是这个版本。

#include <iostream>
#include <functional>
#include <unordered_map>

template<class T>
void foo(
  const std::function<void (std::unordered_map<int, T>&&)>& bar
) {
  std::unordered_map<int, T> myMap;
  bar(myMap);
}

int main() {
  foo([](auto&& m) {
  });
}

最佳答案

显示的代码尝试为以下类型推导出 TU

std::function<void (std::unordered_map<U, T>&&)>

推导尝试是针对传递给模板函数的lambda参数:

[&map1](auto&& map2) {}

问题是 lambda 不是某种 std::function。这是一个:

...temporary object of unique unnamed non-union non-aggregate class type, known as "closure" type,...

( Cite )

换句话说,lambda 对象是具有执行 lambda 代码的 operator() 的类的实例(并且捕获的对象被转化为未命名类的成员)。因此,由于它不是 std::function,因此无法从中推断出 std::function 的类型。

由于它是可调用类型,因此可以将其转换为 std::function,但:

bar(static_cast<std::function<void(std::unordered_map<std::string, T> &&)>>
      ([&map1](auto&& map2) {
          // do some things with map1 and map2
      }));
}

这将使 bar() 模板函数得到识别。

但是显示的代码还有第二个问题:

  if (rand() % 2 > 0) {
    baz(getInt2TMap<T>());
  } else {
    baz(getStr2TMap<T>());
  }

根据掷骰子的情况,代码将尝试将无序字符串映射或无序整数映射传递给 baz()

那是……行不通的。在游戏的这个阶段,baz 是某种类型的 std::function。它不是模板。因此,它只能采用一种类型的参数。

如果您添加 static_cast,并使 bar() 成为:

 baz(getStr2TMap<T>());

为了匹配调用者正在传递无序字符串映射的事实,生成的代码应该编译。

bar() 中发生的事情是一个单独的问题。使用 static_cast 回答了如何识别候选模板 bar 的问题。

关于传递 lambda 作为 std::function 的参数时,C++ 候选模板忽略错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41071574/

相关文章:

c++ - 与函数指针、__cdecl 和模板的混淆

c++ - 如何将 vector <cv::Point2d> 转换为 vector <cv::Point>?

c++ - 我可以从 new[] 分配一个指向字符数组的指针吗

c++11 - C++ ofstream 与 basic_ofstream

c++ - 基于宏的计数器

c++ - 使用 std::for_each lambda 函数时出错

c++ - 如何在std::function上使用模板扩展

c++ - 是否可以通过桶迭代器从 std::unordered_set 中删除元素?

C++ 使用函数参数类型进行模板参数推导

c++ - 如何将对象传递给本地对象方法?