简体   繁体   中英

C++ generic Method giving 'no matching function for call' error

This is my first time coding in C++ and I'm new to the generics in C++. I'm trying to make a little program that basically represents a graph and then traverse that graph using Breadth-First Search. I have made what I think is a generic graph and a generic BFS method. I have included all the code in case there is something I missed.

Here is the exact error:

no matching function for call to 'bfs(const char [4], Graph<std::__cxx11::basic_string<char> >&)
  bfs("One", graph2);

Here is the code:

Graph.h :

#ifndef GRAPH_H
#define GRAPH_H

#include <map>
#include <iostream>
#include <list>
#include <set>

using namespace std;

template <class T>
class Graph{

    private:
        map<T, set<T>> adj_list;

    public:
        Graph();
        void addVertex(T val, set<T> edges);
        set<T> getNeighbours(T vertex);
};

#endif

Graph.cpp :

#include <iostream>
#include "Graph.h"

#include <string>

using namespace std;

template <class T>
Graph<T>:: Graph(){
    ;
}

// add vertex method
template <class T>
void Graph<T>:: addVertex(T val, set<T> edges){
    //if the vertex is already created, the add the list of connections
    //to that vertex, otherwise create a new vertex and create a new set
    //of connections for the vertex
    class map<T, set<T>> :: iterator it = adj_list.find(val);
    if (it != adj_list.end()){
        it->second.insert(edges.begin(), edges.end());
    }
    else{
        adj_list.insert({val, edges});
    }

    // for all the connections, add the vertex to their corresponding
    // connection set
    for (T elem: edges){
        class map<T, set<T>> :: iterator it1 = adj_list.find(elem);
        if (it1 != adj_list.end()){
            it1->second.insert(val);
        }
        else{
            adj_list.insert({elem, {val}});
        }
    }
}

//get neighbours of given vertex
template <class T>
set<T> Graph<T>:: getNeighbours(T vertex){
    return adj_list[vertex];
}

//override << operator. Display the adjacency list
template <class T>
inline ostream& operator<<(ostream& out, const Graph<T>& H){
    out << "{\n";
    for (class map<T, set<T>>::const_iterator it = H.adj_list.begin(), end = H.adj_list.end(); it != end;++it){
        out << to_string(it->first) + " : ";
        for (class set<T>::const_iterator lit = it->second.begin(), lend = it->second.end(); lit!= lend; ++lit){
                if (distance(next(lit), lend) == 0){
                    out << to_string(*lit);
                }
                else{
                    out << to_string(*lit) + ", ";
                }
        }
        out << "\n";
    }

    out << "}" << endl;
    return out;
}

main.cpp :

#include <iostream>
#include "Graph.h"
#include "Graph.cpp"
#include <queue>

using namespace std;

template <class T> 
void bfs(T vertex, Graph<T> graph){
    // queue for bfs and set for checking if nodes have been visited
    queue<T> myQueue; 
    set<T> visited;

    //enqueue the vertex
    myQueue.push(vertex);

    //while there are still nodes to be visited
    while (!myQueue.empty()){

        //get the node to be searched next and add it to visited
        T curr = myQueue.front();
        myQueue.pop();
        visited.insert(curr);
        cout << "Visiting node:" << curr << endl;

        //add all the nodes neighbours to the queue
        for (T elem: graph.getNeighbours(curr)){
            class set<T> :: iterator it = visited.find(elem);

            //if the neighbours of the current node have been visitted then dont add to queue
            if (it == visited.end()){
                myQueue.push(elem);
            }
        }
    }
}


int main(){
    //initialize graph
    Graph<int> graph1;

    //create simple tree
    //          1
    //        /   \
    //       2     3
    //      / \   / \
    //     4   5 6   7
    set<int> connections1 = {2, 3};
    set<int> connections2 = {4, 5};
    set<int> connections3 = {6, 7};

    graph1.addVertex(1, connections1);
    graph1.addVertex(2, connections2);
    graph1.addVertex(3, connections3);

    // perfrom BFS
    bfs(1, graph1);

    Graph<string> graph2;
    set<string> connectionsS1 = {"Two", "Three"};
    set<string> connectionsS2 = {"Four", "Five"};
    set<string> connectionsS3 = {"Six", "Seven"};

    graph2.addVertex("One", connectionsS1);
    graph2.addVertex("Two", connectionsS2);
    graph2.addVertex("Three", connectionsS3);

    bfs("One", graph2);

    return 0;
}

The compiler is deducing the template type for bfs from the arguments you pass it. As the first argument is of type const char[4] it chooses that as the template type, this then fails as Graph<string> is not convertible to Graph<const char[4]> .

You can either pass a string as the first argument:

bfs(string("One"), graph2);

Or explicitly tell the compiler the template type:

bfs<string>("One", graph2);

I presume that bfs should also be taking the graphs by reference rather than copying them?

void bfs(T vertex, const Graph<T>& graph)

You shouldn't include .cpp files, I guess you're doing so to avoid linker errors due to Why can templates only be implemented in the header file?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM