c++ - 我怎样才能解决这个歧义。内存乐趣?

标签 c++ templates generics mem-fun

为了练习,我再次熟悉的主题之一是树木。深度优先搜索和广度优先搜索的区别仅在于支持算法的数据结构的选择。

我想我可以编写一个通用的树搜索,我可以使用模板将其提供给堆栈 (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 来帮助你。在您的情况下,您可以使用以下两个选项进行转换:

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 时,您试图将一个临时对象绑定(bind)到一个引用。连同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 );

通过这些更改,代码对我有用。

关于c++ - 我怎样才能解决这个歧义。内存乐趣?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15251124/

相关文章:

c++ - 如何包含文件夹中的所有源文件? (C++,MS VS 2013)

使用模板实现接口(interface)的c++编译错误

c++ - 重载模板解析

Java泛型继承

java - 为什么 varargs (Class<? extends Throwable>... t) "unchecked or unsafe"操作?

c++ - 在 Visual C++ 2010 Express 中安装 OpenCV 2.4.3

c++ - 关于alloca的使用和滥用

c++ - 二维数组中的预期常数

c++ - 运算符(operator)填写的模板

c# - 如何在 AutoFac 中注册具有接口(interface)类型的通用接口(interface)?