C++ 模板上的隐藏错误
对于我目前正在编写的一段代码,我看到的错误消息让我相当困惑。我已经尝试提取最相关的代码片段,以使其易于阅读 我看到的错误是: 错误:调用“C++ 模板上的隐藏错误,c++,templates,c++11,C++,Templates,C++11,对于我目前正在编写的一段代码,我看到的错误消息让我相当困惑。我已经尝试提取最相关的代码片段,以使其易于阅读 我看到的错误是: 错误:调用“Map(Print&,std::shared_ptr&)”时没有匹配的函数 注意:模板参数扣除/替换失败: 无法将“p”(键入“Print”)转换为键入“int” 为什么编译器试图将Print转换为int template<typename T> class LinkedList { public: using NodeType = std::
Map(Print&,std::shared_ptr>&)
”时没有匹配的函数 注意:模板参数扣除/替换失败: 无法将“
p
”(键入“Print
”)转换为键入“int
”
为什么编译器试图将Print
转换为int
template<typename T>
class LinkedList
{
public:
using NodeType = std::shared_ptr<LinkedList>;
... Other things
}
template<class Func, typename T>
typename LinkedList<T>::NodeType Map(Func func, typename LinkedList<T>::NodeType seq)
{
// Some stuff
}
class Print
{
public:
int operator()(int i)
{
cout << i << endl;
return i;
}
};
void main()
{
Print p;
auto one = std::make_shared< LinkedList <int>> ();
auto result = Map<int>(p, one); << ---- Error
}
模板
类链接列表
{
公众:
使用NodeType=std::shared\u ptr;
…其他事情
}
模板
typename LinkedList::NodeType映射(Func-Func,typename LinkedList::NodeType seq)
{
//一些东西
}
类打印
{
公众:
int运算符()(int i)
{
cout如果我这样做,我会将Map定义为LinkedList的内联好友。这消除了依赖类型推断的问题,因此您可以在不使用任何显式模板参数的情况下调用Map
请记住,编译器找到这样定义的函数的唯一方法是使用参数相关的查找——因此它只在LinkedList
对象作为函数的参数之一传递时才起作用。此外,内联好友似乎会让人感到不安
但是,清理和简化代码还有很长的路要走
#include <iostream>
#include <memory>
template<typename T>
class LinkedList
{
public:
using NodeType = std::shared_ptr<LinkedList>;
template <typename Func>
friend NodeType Map(Func func, NodeType seq) {
return seq;
}
};
class Print
{
public:
int operator()(int i)
{
std::cout << i << std::endl;
return i;
}
};
int main()
{
Print p;
auto one = std::make_shared< LinkedList<int> >();
auto result = Map(p, one);
}
#包括
#包括
模板
类链接列表
{
公众:
使用NodeType=std::shared\u ptr;
模板
好友节点类型映射(Func-Func,节点类型seq){
返回顺序;
}
};
类打印
{
公众:
int运算符()(int i)
{
std::cout在更好地理解OP的目标之后,我添加了一个新的答案。我的第一个答案解决了编译一些示例代码时遇到的与依赖模板类型参数相关的困难,因此我认为这仍然是一个有效的答案
这个答案演示了如何创建一个自定义容器类,以及如何编写一个泛型的Map
函数来迭代容器,为每个元素调用一个自定义函数对象,并将每个结果添加到另一个容器中,该容器最终由函数返回
本例中的容器是一个链表,由一组最小的特性定义,仅足以编译和运行本例
链表类提供了返回用于遍历列表的迭代器对象的begin()
和end()
函数。此处仅定义了非常量版本,当LinkedList对象为常量时,还应添加用于返回常量迭代器的版本
此处的Map
函数将一个函子和一个容器对象作为参数。所有参数类型都是推导出来的,因此不需要显式提供模板参数。容器是按值传递的,以避免LinkedList中常量的正确性问题,也因为LinkedList
(默认值)复制构造函数不需要做很多工作——它只需要复制两个共享的\u ptr
对象,而不是对所有包含的数据执行深度复制
这个Map
非常简单,额外的改进版本可能需要两个迭代器(一个begin和end)、对容器对象的const引用(以避免无用的复制),或者使用类型特征来处理需要以特殊方式访问的容器
在这里,Map
应该与其他容器一起使用,比如std::vector,因为它使用标准迭代器API
LinkedList的原始版本只是作为指向单个列表节点的指针进行维护。在下面的代码中,LinkedList
是一个真正的容器对象,它保持(智能)指向第一个和最后一个节点
对象的指针。我们需要在此处访问指向头
和尾
节点的指针,因此仅将指针指向一个节点是不够的
#include <iostream>
#include <memory>
#include <string>
template<typename T>
class LinkedList {
public:
struct Node;
using NodeType = std::shared_ptr<Node>;
struct Node {
NodeType next;
T value;
};
class forward_iterator {
NodeType cur_node;
public:
forward_iterator() {}
forward_iterator(NodeType cur_node) : cur_node(cur_node) {}
T& operator * () { return cur_node->value; }
forward_iterator& operator ++ () { cur_node = cur_node->next; return *this; }
bool operator == (const forward_iterator& it) const { return cur_node == it.cur_node; }
bool operator != (const forward_iterator& it) const { return !operator == (it); }
};
void push_back(const T& t) {
NodeType node = std::make_shared<Node>();
if(tail) {
tail->next = node;
tail = node;
} else {
head = tail = node;
}
node->value = t;
}
forward_iterator begin() { return forward_iterator(head); }
forward_iterator end() { return forward_iterator(); }
protected:
NodeType head, tail;
};
inline std::string upper_case(const std::string& s) {
std::string r;
for(auto c : s) {
if(c >= 'a' && c <= 'z') c = c - 'a' + 'A';
r.push_back(c);
}
return r;
}
template <typename Func, typename S>
inline S Map(Func func, S seq) {
S result;
for(const auto& elem : seq) {
result.push_back(func(elem));
}
return result;
}
int main() {
// add strings to a LinkedList of strings named "original"
static const char* my_data[] = { "Hello", "1234", "John Cena", "xd" };
LinkedList<std::string> original;
for(auto cstr : my_data) { original.push_back(cstr); }
// dump "original" to cout
std::cout << "-- original --\n";
for(const auto& s : original) { std::cout << s << '\n'; }
std::cout << '\n';
// Run the generic Map function with "original" as input
// A lambda will be called for each element and
// its returned value added to the result, named "mapped".
// A functor object may be used in place of the lambda
auto mapped = Map(
[](const std::string& s) { return upper_case(s); },
original);
// dump "mapped" to cout
std::cout << "-- mapped --\n";
for(const auto& s : mapped) { std::cout << s << '\n'; }
std::cout << '\n';
}
#包括
#包括
#包括
模板
类链接列表{
公众:
结构节点;
使用NodeType=std::shared\u ptr;
结构节点{
下一个节点类型;
T值;
};
类前向迭代器{
节点类型cur_node;
公众:
前向迭代器(){}
前向迭代器(NodeType cur_node):cur_node(cur_node){}
T运算符*(){返回当前节点->值;}
正向迭代器和运算符++(){cur\u node=cur\u node->next;返回*this;}
bool操作符==(const forward_iterator&it)const{return cur_node==it.cur_node;}
布尔运算符!=(常量前向迭代器&it)常量{return!运算符==(it);}
};
无效推回(施工T&T){
NodeType node=std::make_shared();
如果(尾部){
tail->next=节点;
尾=节点;
}否则{
头=尾=节点;
}
节点->值=t;
}
前向迭代器begin(){返回前向迭代器(head);}
前向迭代器end(){返回前向迭代器();}
受保护的:
头、尾有节;
};
内联std::string大写字母(const std::string&s){
std::字符串r;
用于(自动c:s){
如果(c>='a'&&c)您告诉编译器Func=int
这里Map(p,one)
。您需要Map(p,one)
auto result=Map(p,one);
这不是您试图将pPrint
引用到int
?如果您交换模板参数,您可以指定Map(p,one)
并将Func
推导出为Print
。啊,当然可以。Map facepalm。谢谢你的帮助。@melak47我想这也行,但我想知道为什么这种格式会导致错误。事实上,这是我的第一个实现。我正在尝试在Clojure/Lisp中模拟Map函数。使Map成为LinkedList意味着它可以访问私有成员,而Map不是LinkedList的属性