以下代码在Coliru上使用其默认编译参数进行了所有尝试
g-std=c 17-O2-Wall-docantic-pthread-main.cpp
假设我们想制作一个保存数据“容器”的包装器(例如,向量、列表、任何保存一个可以模板化的值的数据结构)。然后,稍后我们要使用助手函数将其转换为另一种类型。这个函数可以被多次调用,只需编写<代码>转换(…) ,而不是像转换
还假设我们有这个(请注意,类似于std::move、explicit、通过std::copy()在convert函数中复制等等)。
尝试1:使用下面的std::function
失败:
#include <functional>
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>
using std::string;
using std::vector;
template <template<typename...> class DataContainer, typename T, typename... TArgs>
struct Wrapper {
DataContainer<T, TArgs...> dataContainer;
Wrapper(DataContainer<T, TArgs...> container) : dataContainer(container) { }
// Using parameter type std::function<V(T)> fails here
template <typename V, typename... VArgs>
DataContainer<V, VArgs...> convert(std::function<V(T)> f) {
DataContainer<V, VArgs...> output;
for (T t : dataContainer)
output.emplace_back(f(t));
return output;
}
};
int main() {
vector<int> nums = {123};
Wrapper w{nums};
vector<string> intVec = w.convert(std::to_string);
std::cout << intVec.front() << std::endl;
}
这不会编译,并给出错误
主要的cpp:在函数“int main()”中:
main.cpp:37: 57:错误:没有匹配函数调用'Wrapper
vector<string> intVec = w.convert(std::to_string);
^
main.cpp:17: 36:注:候选:'模板DataContainer Wrapper::conversion(std::function)[with V=V; VArgs={VArgs...}; DataContainer=std::向量;T=int; TArgs={std::allocator}]'
DataContainer<V, VArgs...> convert(std::function<V(T)> f) {
^~~~~~~
main.cpp:17: 36:注意:模板参数推导/替换失败:
main.cpp:37: 57:注意:不匹配的类型'std::function'和'std::__cxx11::string()(长双倍)'{aka'std::__cxx11::basic_string()(长双倍)'}
vector<string> intVec = w.convert(std::to_string);
^
main.cpp:37: 57:注意:不匹配的类型'std::function'和'std::__cxx11::string()(int)'{aka'std::__cxx11::basic_string()(int)'}
主要的cpp:37:57:注意:无法推断模板参数“V”
我尝试创建自己的独立静态函数,以防重载弄乱它,但我得到了同样的错误,即:
不匹配的类型“std::function”和“int()(std::\ucx11::string){aka“int()(std:\ucx11::basic\u string)}
但是,当我将std::函数更改为函数指针时:
// Now using V(*f)(T) instead
template <typename V, typename... VArgs>
DataContainer<V, VArgs...> convert(V(*f)(T)) {
DataContainer<V, VArgs...> output;
for (T t : dataContainer)
output.emplace_back(f(t));
return output;
}
现在可以打印出来了
123个
这给了我想要的,但现在我必须在convert上指定类型,如。转换
尝试2:
我想我可以做STL库所做的事情,它像这样模板函数:
template <typename Func, typename V, typename... VArgs>
DataContainer<V, VArgs...> convert(Func f) {
DataContainer<V, VArgs...> output;
for (T t : dataContainer)
output.emplace_back(f(t));
return output;
}
但编译失败:
主要的cpp:在函数“int main()”中:
主要的cpp:45:57:错误:调用“包装器”时没有匹配的函数
vector<string> intVec = w.convert(std::to_string);
^
主要的cpp:33:36:注意:候选者:“模板数据容器包装器::convert(Func)[其中Func=Func;V=V;VArgs={VArgs…};数据容器=标准::向量;T=int;TArgs={std::分配器}]'
DataContainer<V, VArgs...> convert(Func f) {
^~~~~~~
main.cpp:33: 36:注意:模板参数推导/替换失败:
main.cpp:45:57:注意:无法推导模板参数“函数”
vector<string> intVec = w.convert(std::to_string);
^
我想要的就是排队
vector<string> intVec = w.convert(std::to_string);
无需在convert右侧编写任何模板即可工作。
我做错了什么?我可以用函数指针得到我想要的东西,但似乎我必须编写一系列重载,如V(*f)(T)
,V(*f)(const
尝试3:
除非我指定类型,否则lambda不起作用,这意味着我必须这样做:
vector<string> intVec = w.convert<string>([](int i) { return std::to_string(i); });
我想:
vector<string> intVec = w.convert([](int i) { return std::to_string(i); });
当我没有指定类型时会发生这种情况(为什么它不能推断出来?)
主要的cpp:在函数“int main()”中:
主要的cpp:45:82:错误:调用“包装器”时没有匹配的函数
vector<string> intVec = w.convert([](int i) { return std::to_string(i); });
^
main.cpp:17: 36:注:候选:'模板DataContainer Wrapper::conversion(std::function)[with V=V; VArgs={VArgs...}; DataContainer=std::向量;T=int; TArgs={std::allocator}]'
DataContainer<V, VArgs...> convert(std::function<V(T)> f) {
^~~~~~~
main.cpp:17: 36:注意:模板参数推导/替换失败:
主要的cpp:45:82:注意:“main()::”不是从“std::function”派生的
vector<string> intVec = w.convert([](int i) { return std::to_string(i); });
^
简而言之,所有这些都是因为我必须不断复制粘贴每个使用函数指针和std::f块重载执行此类操作的函数,然后如果我想支持右值、左值、const左值的函数参数...我得到了函数的组合爆炸,这使得工作解决方案一团糟。我不知道这是不可避免的,还是我错过了什么让它推断类型,同时允许我传入函数名称或lambda。
这是每个人都会犯的错误:
template <typename V>
DataContainer<V> convert(std::function<V(T)> f);
我理解人们为什么这么做,这显然是正确的做法,对吗?甚至在这里写了很多。关键是:推导std::函数总是错误的。您无法推断这一点,因为它不允许转换,即使您可以推断,它也会增加您不想要的开销。
不幸的是,没有等效的干净语言解决方案。我所说的清洁是指,在某种程度上,T和V是如此清晰地联系在一起,就像上面的非溶液一样。
你真正想做的是:
template <typename F, typename V = std::invoke_result_t<F, T>>
DataContainer<V> convert(F f);
也就是说,我们只是推断类型——然后使用类型特征来找出答案。
std::to\u string的问题是完全独立的-您不能将重载的函数或函数模板传递到函数模板中。你总是要把它包在一个小羊肚里。
我的分类测试应用程序有一个问题,我使用了一个比较器。我收到一条信息: 线程“主”java.lang 中的异常:未解决的编译问题:无法推断排序器的类型参数 对于该代码: 分拣机类: 可比接口: id比较器类: 比较器接口: 这样用有什么错?我怎样才能做得更好?
我仍然在玩我的日历,我已经设法将 https://github.com/SundeepK/CompactCalendarView 整合到我的一个片段中。只剩下一个错误,我做了一些研究,其他人也遇到了问题,例如使用ArrayList 示例代码: IDE说: 注:C:...\Uebersicht.java使用或覆盖不推荐使用的API。注意:用-Xlint:deprecation重新编译以获得详细信息。
我目前有一个,但是为了灵活性,我希望能够分配一个lambda表达式,将作为映射中的值返回。 所以我创建了这个模板类: 并像这样使用它: IntelliSense提供了更多信息: 多个操作符“=”匹配这些操作数:function“valueorfunction::operator=(const std::function&other)[with T=std::wstring]”function“va
我需要 Kotlin 中的一个集合来仅包含实现给定接口的元素。 例如:包含动物集合的地图: 通过阅读文档、博客和SO问题,我编写了使用Generics in关键字的代码: 现在我想在Test类中添加一个读取“data”内容的方法,例如将其打印到控制台: 如果我这样做,我会遇到编译错误: 我的解决方案是强制我的动物进入一个ArrayList 但是我不确定这是编写这种代码的最好方式。有没有更好的方式告
我最近使用Kotlin开发了Android应用程序,但我收到以下错误 无法推断此参数的类型。请明确指定 在我的课堂下面,我收到了错误。
std=C14的g在函子类的模板方法(本身不是模板)上给我一个“无法推断模板参数'Key'”错误。我不知道为什么。代码看起来应该可以工作。 我正在实现一个2-3树,它有一个采用函子的层次顺序遍历方法。操作人员tree23代码基本上是这样的: 级别顺序遍历调用仿函数的函数调用操作符,向其传递两个参数。 函子非常简单: