我怎样才能解决这个模棱两可的问题呢?mem_fun
How can I solve this ambiguousity wrt. mem_fun?
为了练习,我再次熟悉的主题之一是树。深度优先搜索和宽度优先搜索的区别在于,它们只在选择支持算法的数据结构上有所不同。
我想我可以写一个普通的树搜索,我将提供堆栈(DFS)或队列(BFS)使用模板。stack
和queue
很好,它们的添加和删除成员具有相同的名称。不幸的是,访问函数一度被称为top
和front
。正因为如此,我没有完全到达我想要的地方。没有lambda:
template<typename T, typename D, typename G>
bool ts(Tree<T> const & tree, T const value, D & ds, G getter)
{
if (empty(tree))
{
return false;
}
ds.push(tree.Root);
while (!ds.empty())
{
auto const current = getter();
ds.pop();
if (current->Value == value)
{
return true;
}
if (current->Left)
{
ds.push(current->Left);
}
if (current->Right)
{
ds.push(current->Right);
}
}
return false;
}
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
stack<typename Tree<T>::Node const * const> ds;
return ts(tree, value, ds, [&ds](){ return ds.top(); });
}
template<typename T>
bool bfs(Tree<T> const & tree, T const value)
{
queue<typename Tree<T>::Node const * const> ds;
return ts(tree, value, ds, [&ds](){ return ds.front(); });
}
我认为我应该能够使用mem_fun
(或mem_fun_ref
)来提供相应的访问功能。我试着
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
typedef stack<typename Tree<T>::Node const * const> DataStructure;
return ts(tree, value, DataStructure(), mem_fun(&DataStructure::top));
}
但是随后编译器抱怨有歧义(在const
和非const
版本之间)。
所以我搜索了互联网,了解到我应该明确地提供模板类型。
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
typedef stack<typename Tree<T>::Node const * const> DataStructure;
return ts(tree, value, DataStructure(), mem_fun</*???*/>(&DataStructure::top));
}
遗憾的是,没有一个的可能性??,我可以提出满意的编译器
谁能给我点提示吗?更新:这里有一个完整的工作示例(除非您定义了NO_LAMBDA):
#include <iostream>
#include <stack>
#include <functional>
using namespace std;
template<typename T>
struct Tree
{
struct Node
{
T Value;
Node * Left;
Node * Right;
Node(T value) : Value(value), Left(nullptr), Right(nullptr) {}
virtual ~Node()
{
if (Left) delete Left;
if (Right) delete Right;
}
};
Node * Root;
Tree() : Root(nullptr) {}
virtual ~Tree() { if (Root) delete Root; }
};
template<typename T> void insert(typename Tree<T>::Node * node, T const & value)
{
typename Tree<T>::Node ** selected = &(value < node->Value ? node->Left : node->Right);
if (*selected)
insert(*selected, value);
else
*selected = new typename Tree<T>::Node(value);
}
template<typename T> void insert(Tree<T> & tree, T value)
{
if (!tree.Root)
tree.Root = new typename Tree<T>::Node(value);
else
insert(tree.Root, value);
}
template<typename T, typename D, typename G>
bool ts(Tree<T> const & tree, T const value, D & ds, G getter)
{
if (!tree.Root) return false;
ds.push(tree.Root);
while (!ds.empty())
{
auto const current = getter();
ds.pop();
if (current->Value == value) return true;
if (current->Left) ds.push(current->Left);
if (current->Right) ds.push(current->Right);
}
return false;
}
template<typename T>
bool dfs(Tree<T> const & tree, T const value)
{
typedef typename Tree<T>::Node const * DataStructureContent;
typedef stack<DataStructureContent> DataStructure;
#ifdef NO_LAMBDA // With this defined, it breaks.
return ts(tree, value, DataStructure(),
mem_fun(static_cast<DataStructureContent (DataStructure::*)() const>(&DataStructure::top)));
#else // This works.
DataStructure ds;
return ts(tree, value, ds, [&ds] () { return ds.top(); });
#endif
}
int main()
{
Tree<int> tree;
insert(tree, 5);
insert(tree, 2); insert(tree, 1); insert(tree, 3);
insert(tree, 7); insert(tree, 6); insert(tree, 9);
cout << "DFS(7) -> " << dfs(tree, 7) << endl;
cout << "DFS(8) -> " << dfs(tree, 8) << endl;
return 0;
}
可以将成员函数指针强制转换为所需的类型:
mem_fun( static_cast< R (DataStructure::*)( Args... ) >( &DataStructure::top ) )
或
mem_fun( static_cast< R (DataStructure::*)( Args... ) const >( &DataStructure::top ) )
使用合适的R
作为结果类型,Args...
作为参数。
编辑:你在完整的例子中犯了两(三)个错误:
a)强制转换需要精确,也就是说您需要提供正确的返回类型。幸运的是,std::stack
有类型定义来帮助您。在您的情况下,您可以使用以下两个选项强制转换:
typedef typename DataStructure::reference (DataStructure::*non_const_top)();
mem_fun( static_cast< non_const_top >( &DataStructure::top ) )
或
typedef typename DataStructure::const_reference (DataStructure::*const_top)() const;
mem_fun( static_cast< const_top >( &DataStructure::top ) )
b)在调用ts
时试图将临时对象绑定到引用。与a)一起,将代码更改为:
DataStructure ds;
typedef typename DataStructure::reference (DataStructure::*non_const_top)();
return ts(tree, value, ds, mem_fun(static_cast<non_const_top>(&DataStructure::top)));
c)在ts
中,您尝试在没有对象的情况下调用getter
。你需要把它改成:
auto const current = getter( &ds );
定义几个typedefs
typedef typename DataStructure::reference reference;
typedef typename DataStructure::const_reference const_reference;
typedef reference (DataStructure::*top_type)(); //non-const version
typedef const_reference (DataStructure::*ctop_type)() const;//const version
然后使用任何你需要的。
在发布的代码中,你需要const版本,所以这样写:
mem_fun( static_cast<ctop_type>(&DataStructure::top ))
类型转换帮助编译器选择你想要使用的版本。
顺便说一下,在c++ 11中,std::mem_fun
是不支持的 。它还增加了一个叫做std::mem_fn
的功能。注意拼写上的不同。有关详细信息,请参阅本主题:
- std::mem_fun vs std::mem_fn
您需要的是std::bind
,而不是std::mem_fun
(或std::mem_fn
):
现在可以运行了:
- <
- 在线演示/gh>
你调用getter
的方式表明你需要std::bind
,因为你像这样调用getter
:
auto const current = getter();
如果getter
是一个从std::mem_fun
返回的对象,这是一个错误,在这种情况下,它应该像这样被调用:
auto const current = getter(&ds);
看这个演示:
- <
- 在线演示/gh>
或者如果只是传递指向成员的指针,则调用as:
auto const current = (ds.*getter)();
参见:Online Demo
比较这三个。看看区别吧!
希望对你有帮助。
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- setlocale的C++土耳其字符串问题
- 如何重构类层次结构以避免菱形问题
- 基于boost的程序的静态链接——zlib问题
- C++格式化输出问题
- 使用mongocxx驱动程序时包含头文件问题