将 lambda 作为 std::function 的参数传递时,C++ 候选模板忽略错误
C++ Candidate Template Ignored error when passing lambda as argument for 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) {
});
}
显示的代码尝试为以下类型推导 T
和 U
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 对象是 class 的一个实例,带有执行 lambda 代码的 operator()
(并且捕获的对象被转化为未命名的 class).因此,由于它不是 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
被识别的问题。
Sam 很好地观察了 U
在 bar
中的不一致之处。但是在您的简单示例中,当您可以编写时,为什么还要经历 const std::function<void (std::unordered_map<int, T>&&)>&
的所有麻烦:
#include <iostream>
#include <functional>
#include <unordered_map>
template<class T, class Func>
void foo(
Func bar
) {
std::unordered_map<int, T> myMap;
bar(myMap);
}
int main() {
// needs the hint for T, since it isn't used anywhere
foo<int>([](auto&& m) {
});
}
这是我在 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) {
});
}
显示的代码尝试为以下类型推导 T
和 U
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 对象是 class 的一个实例,带有执行 lambda 代码的 operator()
(并且捕获的对象被转化为未命名的 class).因此,由于它不是 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
被识别的问题。
Sam 很好地观察了 U
在 bar
中的不一致之处。但是在您的简单示例中,当您可以编写时,为什么还要经历 const std::function<void (std::unordered_map<int, T>&&)>&
的所有麻烦:
#include <iostream>
#include <functional>
#include <unordered_map>
template<class T, class Func>
void foo(
Func bar
) {
std::unordered_map<int, T> myMap;
bar(myMap);
}
int main() {
// needs the hint for T, since it isn't used anywhere
foo<int>([](auto&& m) {
});
}