我怎样才能解决这个模棱两可的问题呢?mem_fun

How can I solve this ambiguousity wrt. mem_fun?

本文关键字:问题 mem fun 模棱两可 解决      更新时间:2023-10-16

为了练习,我再次熟悉的主题之一是树。深度优先搜索和宽度优先搜索的区别在于,它们只在选择支持算法的数据结构上有所不同。

我想我可以写一个普通的树搜索,我将提供堆栈(DFS)或队列(BFS)使用模板。stackqueue很好,它们的添加和删除成员具有相同的名称。不幸的是,访问函数一度被称为topfront。正因为如此,我没有完全到达我想要的地方。没有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

比较这三个。看看区别吧!

希望对你有帮助。