Как передать функции в качестве параметров внутри класса? - PullRequest
3 голосов
/ 02 июня 2019

Я пытаюсь передать мою print функцию в качестве параметра через мой inordertraversal класс, который принадлежит шаблонному binarySearchTree. всякий раз, когда я определяю эти функции в main, программа работает нормально, но всякий раз, когда я пытаюсь инкапсулировать их, я получаю сообщение об ошибке:

"expected primary-expression before '&' token"

Это код, который работает

void print(classdatatype& x); 
int main()
{
    binarySearchTree<classdatatype> tree;
    tree.inorderTraversal(print);
    return 0;
}

void print(classdatatype& x)   {  cout << x << " ";      } 

Объявление моего inordertraveral шаблонного класса

template <class elemType>
void binarySearchTree<elemType>::inorderTraversal(void (*visit)(elemType& item))

Я могу показать остальную часть кода, если это необходимо, но все это прекрасно работает

Как только я перенесу эти функции в свой класс, это будет выглядеть так (объявления для print и binarySearchTree находятся в .cpp так же, как они были объявлены выше)

void bst::printfunctions(classdatatype& x)
{
    tree.inorderTraversal(print(classdatatype & x)); //error here
}

void bst::print(classdatatype& x) 
{ 
    cout << x << " "; 
} 

Ошибка в скобках print, я пробовал много разных вещей, но для меня это правильное объявление; поэтому я не знаю, почему это не работает.

Любой совет будет принят с благодарностью.


EDIT : print - это указатель функции для печати сведений о classdatatype, который хранится в двоичном дереве поиска.


EDIT2 : минимальный воспроизводимый пример.

Типы данных такие, какие они есть, и не такие, как в приведенном выше примере. Это настолько просто, насколько я мог это сделать, и в итоге я получил еще одну ошибку, которую не смог исправить, но для целей этого примера это не имеет значения и должно быть проигнорировано. main() включено, но является минимальным и может не соответствовать своей цели, но проблема все равно не в этом.

основной ()

#include <iostream>
#include "windlogtype.h"
using namespace std;

int main()
{
    windlogtype wind;

    ifstream infile("data.txt");
    //for purose of this data is one integer value
    infile >> wind;

    //do something
    //main purpose is to get input
    return 0;
}

класс windlogtype

#include "windlogtype.h"
windlogtype::windlogtype() { }    
windlogtype::windlogtype(int i)     {   num = i; }    
int windlogtype::Getnumber() const  {   return num; }    
void windlogtype::Setnumber(int i)  {   num = i; }    
ostream operator<<(ostream& os, const windlogtype& w)
{
    os << w.Getnumber() << '\n';
    return os;
}

#ifndef WINDLOGTYPE_H
#define WINDLOGTYPE_H

#include <iostream>
using namespace std;

class windlogtype
{
public:
    windlogtype();
    windlogtype(int i);
    int Getnumber() const;
    void Setnumber(int i);
private:
    int num;
};
ostream operator<<(ostream& os, const windlogtype& w);

#endif // WINDLOGTYPE_H

класс binarySearchTree

#include <iostream>
#include <assert.h>
using namespace std;

template <class elemType> struct binaryTreeNode
{
    elemType info;
    binaryTreeNode<elemType>* llink;
    binaryTreeNode<elemType>* rlink;
};

template <class elemType> class binarySearchTree
{
public:
    const binarySearchTree<elemType>& operator=(const binarySearchTree<elemType>&);
    void inorderTraversal(void (*visit) (elemType&));
    binarySearchTree();
    ~binarySearchTree();
    binaryTreeNode<elemType>* root;
private:
    void inorder(binaryTreeNode<elemType>* p, void (*visit) (elemType&));
};

template <class elemType> binarySearchTree<elemType>::binarySearchTree() {
    root = NULL;
}    
template <class elemType> void binarySearchTree<elemType>::inorderTraversal(void (*visit) (elemType& item))
{
    inorder(root, *visit);
}    
template <class elemType> void binarySearchTree<elemType>::inorder(binaryTreeNode<elemType>* p, void (*visit) (elemType& item))
{
    if (p != NULL)
    {
        inorder(p->llink, *visit);
        (*visit)(p->info);
        inorder(p->rlink, *visit);
    }
}

класс bst

#ifndef BST_H
#define BST_H
#include "binarySearchTree.h"
#include "windlogtype.h"
using namespace std;

class bst
{
public:
    bst();
    void InsertTree(windlogtype& newwind);
    void printfunctions(windlogtype& x);
    binarySearchTree<windlogtype>& GetTree();
    void print(windlogtype& x);
private:
    binarySearchTree<windlogtype> treeRoot;
};    
#endif // BST_H

#include "bst.h"

bst::bst(){/*ctor*/ }    
binarySearchTree<windlogtype>& bst::GetTree() {     return treeRoot;  }
void bst::print(windlogtype& x)               {     cout << x << " ";  }
void bst::printfunctions(windlogtype& x)
{
    treeRoot.inorderTraversal(print(windlogtype & x)); // error lies here
}

1 Ответ

3 голосов
/ 02 июня 2019

void bst::print(classdatatype& x) // is a member function

и

void print(classdatatype& x);    // is a free function.

Следовательно, указатели функции для их удержания также будут другими.


ОП упомянул в комментариях, что хочет передать функцию-член print() из класса bst в функцию-член inorderTraversal() класса binarySearchTree<elemType>.В этом случае передачи функции-члена недостаточно, в дополнение к этому также должен быть передан экземпляр класса, к которому будет вызываться функция print.

Функция Lambda может пригодиться, чтобы упростить это, захватывая экземпляр класса bst и передавая inorderTraversal() класса binarySearchTree,

Это означает, что внутри template <class elemType> class binarySearchTree предусмотрено:

template<typename Callable>
void inorderTraversal(Callable visit)
{
    inorder(root, visit);  // simply pass visit further
    // or avoid coping by warapping std::cref(): i.e. inorder(root, std::cref(visit));
}

template<typename Callable>
void inorder(binaryTreeNode<elemType>* p, Callable visit)
{
    if (p != NULL)
    {
        inorder(p->llink, visit);  // or inorder(root, std::cref(visit));
        visit(p->info);            // call directly with parameter
        inorder(p->rlink, visit);  // or inorder(root, std::cref(visit));
    }
}

Внутри bst класса

void printfunctions(windlogtype& x)
{
    // lambda captures the instance by copy
    const auto printThisLogType = [this](windlogtype & x)->void { this->print(x); };
    treeRoot.inorderTraversal(printThisLogType); // pass the callable lambda
}

Вот код компиляции: https://godbolt.org/z/jhCnPs


PS : Другая ошибка была из operator<< класса windlogtype, где вы пропустили возвращение ссылки std::ostream.

Если честно, вы могли бы сделать еще более простой минимальный код, заменив windlogtype на int и показав определения функции-члена рядом с объявлением.Это сделало бы код легко читаемым.

...