使用CMake在CLion中包括.cpp和.h文件

时间:2020-05-06 11:25:38

标签: c++ cmake clion

我有一个结构如下的项目:

CMakeLists.txt
src:
- graph_power.cpp
- graph_power.h
- main.cpp
- utils.cpp
- utils.h
- vertex_cover.cpp
- vertex_cover.h

main.cpp包含main()方法,并使用所有其他文件。 graph_power.cpp使用utils.cpp,因此我在那里写了#include "utils.h"vertex_cover.cpp也使用utils.cpp。头文件基本上包含相应.cpp文件中的所有方法。

utils.cpp实现set_contains()set_union()map_contains(),它们被其他文件使用。

CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(project)

set(CMAKE_CXX_STANDARD 11)

add_executable(project src/main.cpp src/utils.cpp src/graph_power.cpp src/vertex_cover.cpp)

对于所有三个unrecognized external symbolset_contains()set_union()map_contains()都收到LNK错误。我究竟做错了什么?虽然我包括头文件和列出所有要编译的文件应该可以工作吗?我正在使用CLion,如果很重要,src是蓝色的(源文件目录)。

编辑:

main.cpp:

#include <fstream>
#include <iostream>
#include <iterator>
#include <queue>
#include <string>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "vertex_cover.h"
#include "utils.h"
#include "graph_power.h"


using namespace std;


void check_and_add_left(string& curr_line, unordered_map<int, unordered_set<int>>& graph, int vertex,
                        int row, int col, int W)
{
    if (col > 0 && (curr_line[col - 1] == '-' || curr_line[col - 1] == '+'))
    {
        int vertex_2 = index(row, col - 1, W);
        graph[vertex].insert(vertex_2);
        graph[vertex_2].insert(vertex);
    }
}


void check_and_add_right(string& curr_line, unordered_map<int, unordered_set<int>>& graph, int vertex,
                         int row, int col, int W)
{
    if (col < W - 1 && (curr_line[col + 1] == '-' || curr_line[col + 1] == '+'))
    {
        int vertex_2 = index(row, col + 1, W);
        graph[vertex].insert(vertex_2);
        graph[vertex_2].insert(vertex);
    }
}


void check_and_add_above(string& prev_line, string& curr_line, unordered_map<int, unordered_set<int>>& graph,
                         int vertex, int row, int col, int W)
{
    if (row > 0 && (prev_line[col] == '|' || prev_line[col] == '+'))
    {
        int vertex_2 = index(row - 1, col, W);
        graph[vertex].insert(vertex_2);
        graph[vertex_2].insert(vertex);
    }
}


void process_line_tokens(string& prev_line, string& curr_line,
                         unordered_map<int, unordered_set<int>>& graph, int row, int W)
{
    for (int col = 0; col < W; col++)
    {
        char tile = curr_line[col];
        int vertex = index(row, col, W);

        // add vertex to the graph, if it isn't there already and tile isn't empty
        if (graph.count(vertex) == 0 && tile != '.')
        {
            unordered_set<int> empty_set;
            graph[vertex] = empty_set;
        }

        if (tile == '-')  // vertex may be connected to the one to the left/right
        {
            check_and_add_left(curr_line, graph, vertex, row, col, W);
            check_and_add_right(curr_line, graph, vertex, row, col, W);
        }
        else if (tile == '|')
        {
            check_and_add_above(prev_line, curr_line, graph, vertex, row, col, W);
            // can't check below, but can check above while calling this for the next line
        }
        else if (tile == '+')
        {
            check_and_add_left(curr_line, graph, vertex, row, col, W);
            check_and_add_right(curr_line, graph, vertex, row, col, W);
            check_and_add_above(prev_line, curr_line, graph, vertex, row, col, W);
            // can't check below, but can check above while calling this for the next line
        }
        // ignore tile == "." (empty)
    }
}


unordered_map<int, unordered_set<int>> load_graph(ifstream &file, int W, int H)
{
    unordered_map<int, unordered_set<int>> graph;
    string prev_line, curr_line;
    for (int i = 0; i < H; i++)
    {
        getline(file, curr_line);
        process_line_tokens(prev_line, curr_line, graph, i, W);
        prev_line = curr_line;
    }
    return graph;
}


int W;


int main()
{
    ifstream file("../example.txt");
    if (!file)
    {
        cout << "\nUnable to open file!";
        return -1;
    }

    string line;
    getline(file, line);
    istringstream buffer(line);
    vector<string> first_line_tokens{istream_iterator<string>(buffer), istream_iterator<string>()};

    W = stoi(first_line_tokens.at(0));  // grid width
    int H = stoi(first_line_tokens.at(1));  // grid height
    int L = stoi(first_line_tokens.at(2));  // distance between chosen vertices, number of edges
    int K = stoi(first_line_tokens.at(3));  // number of vertices to choose
    getline(file, line);  // ignore second line

    // load graph grid from standard input
    unordered_map<int, unordered_set<int>> graph = load_graph(file, W, H);

    // calculate G^L to solve Independent Set instead of L-distance Independent Set
    // vertices of degree 0 can be added to the solution here
    unordered_set<int> solution = raise_graph_to_power(graph, L);

    // k = V - K - size of already computed part of solution, for use in Vertex Cover
    unsigned int k = graph.size() - K - solution.size();
    k -= solution.size();

    // calculate graph kernel for efficiency
    bool solution_can_exist = kernelize(graph, solution, k);

    if (!solution_can_exist)
    {
        cout << "ERROR: solution can't exist!";
        exit(1);
    }

    if (k > 0)
    {
        // convert to edge list, since I can't manage to debug the hashmap-based Vertex Cover
        vector<pair<int, int>> edge_list = to_edge_list(graph);


    }

    print_solution(solution);

    return 0;
}

utils.cpp:

#include <unordered_set>
#include <unordered_map>
#include <iterator>
#include <iostream>
#include "utils.h"


int W;


int index(int row, int col, int W)
{
    return row * W + col;
}

void print_point(int point)
{
    int row = point / W;
    int col = point % W;
    cout << "(" << row << ", " << col << ")";
}

void print_solution(const unordered_set<int>& solution)
{
    for (auto const& point : solution)
    {
        int row = point / W;
        int col = point % W;
        cout << row << " " << col << "\n";
    }
}

template<class T>
void set_union(unordered_set<T>& add_to, unordered_set<T>& add_from)
{
    add_to.insert(add_from.begin(), add_from.end());
}

template<class T>
bool set_contains(const unordered_set<T>& s, const T& elem)
{
    return s.find(elem) != s.end();
}

template<typename Key, typename Value, typename Arg>
bool map_contains(const unordered_map< Key, Value > m, const Arg& key)
{
    return m.find(key) != m.end();
}

vector<pair<int, int>> to_edge_list(unordered_map<int, unordered_set<int>>& graph)
{
    unordered_set<pair<int, int>> edges;
    for (auto const& vertex : graph)
    {
        int v = vertex.first;
        for (auto const& u : vertex.second)
            v < u ? edges.insert(make_pair(v, u)) : edges.insert(make_pair(u, v));
    }

    vector<pair<int, int>> edge_list(edges.size());
    copy(edges.begin(), edges.end(), edge_list.begin());
    return edge_list;
}

utils.h:

#ifndef UTILS_H
#define UTILS_H

#include <unordered_map>
#include <unordered_set>

using namespace std;

int index(int row, int col, int W);

void print_point(int point);

void print_solution(const unordered_set<int>& solution);

template<class T>
void set_union(unordered_set<T>& add_to, unordered_set<T>& add_from);

template<class T>
bool set_contains(const unordered_set<T>& s, const T& elem);

template<typename Key, typename Value, typename Arg>
bool map_contains(unordered_map<Key, Value> m, const Arg& key);

namespace std
{
    // enables using pairs in sets
    template <> struct hash<pair<int, int>>
    {
        inline size_t operator()(const pair<int, int> &v) const
        {
            hash<int> int_hasher;
            return int_hasher(v.first) ^ int_hasher(v.second);
        }
    };
}

vector<pair<int, int>> to_edge_list(unordered_map<int, unordered_set<int>>& graph);


#endif //UTILS_H

graph_power.cpp:

#include <utility>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include "utils.h"
#include "graph_power.h"


unordered_set<pair<int, int>> edge_adding_BFS(unordered_map<int, unordered_set<int>>& graph, int source, int power)
{
    unordered_set<pair<int, int>> edges_to_add;
    unordered_set<int> visited;
    unordered_map<int, int> distances;
    distances[source] = 0;
    queue<int> queue;
    queue.push(source);

    while (!queue.empty())
    {
        int u = queue.front();
        queue.pop();
        visited.insert(u);
        for (auto const& v : graph[u])
        {
            if (!set_contains(visited, v))
            {
                visited.insert(v);
                distances[v] = distances[u] + 1;
                edges_to_add.insert(make_pair(source, v));
                if (distances[v] < power)
                    queue.push(v);
            }
        }
    }

    return edges_to_add;
}

unordered_set<int> raise_graph_to_power(unordered_map<int, unordered_set<int>>& graph, int power)
{
    unordered_set<int> solution;
    unordered_set<pair<int, int>> edges_to_add;
    for (auto const& vertex : graph)
    {
        int source = vertex.first;
        // if we have a vertex of degree 0, we just add it to the solution and go on
        if (vertex.second.empty())
            solution.insert(source);
        else
        {
            unordered_set<pair<int, int>> new_edges = edge_adding_BFS(graph, source, power);
            set_union(edges_to_add, new_edges);
        }
    }

    // remove vertices of degree 0 from the graph (they're already in the solution)
    for (auto const& v : solution)
        graph.erase(v);

    for (auto const& edge : edges_to_add)
    {
        int u = edge.first;
        int v = edge.second;
        graph[v].insert(u);
        graph[u].insert(v);
    }

    return solution;
}

graph_power.h:

#ifndef GRAPH_POWER_H
#define GRAPH_POWER_H

unordered_set<pair<int, int>> edge_adding_BFS(unordered_map<int, unordered_set<int>>& graph, int source, int power);

unordered_set<int> raise_graph_to_power(unordered_map<int, unordered_set<int>>& graph, int power);

#endif //GRAPH_POWER_H

vertex_cover.cpp:

#include <vector>
#include <utility>
#include <unordered_set>
#include <unordered_map>
#include "utils.h"
#include "vertex_cover.h"

using namespace std;

bool kernelize(unordered_map<int, unordered_set<int>>& graph, unordered_set<int>& solution, unsigned int& k)
{
    while (true)
    {
        unordered_set<int> to_remove;
        for (auto const& vertex : graph)
        {
            int v = vertex.first;
            if (vertex.second.size() == 1)
            {
                int u = *vertex.second.begin();
                solution.insert(u);

                to_remove.insert(u);
                to_remove.insert(v);

                k -= 1;
                break;
            }
            else if (vertex.second.size() > k)
            {
                solution.insert(v);
                to_remove.insert(v);
                k -= 1;
                break;
            }
        }

        if (!to_remove.empty())
        {
            for (auto const& v : to_remove)
            {
                unordered_set<int> neighbors;
                if (map_contains(graph, v))
                    neighbors = graph[v];
                else
                    continue;

                graph.erase(v);

                for (auto const& u : neighbors)
                {
                    if (!map_contains(graph, u) || !set_contains(graph[u], v))
                        continue;

                    graph[u].erase(v);

                    if (graph[u].empty())
                        graph.erase(u);
                }
            }
        }
        else
            break;
    }

    return graph.size() <= k * k;
}

bool vertex_cover(vector<pair<int, int>>& graph, unordered_set<int>& solution, unsigned int& k)
{
    return false;
}

vertex_cover.h:

#ifndef VERTEX_COVER_H
#define VERTEX_COVER_H

#include <unordered_set>

using namespace std;

bool kernelize(unordered_map<int, unordered_set<int>>& graph, unordered_set<int>& solution, unsigned int& k);

bool vertex_cover(vector<pair<int, int>>& graph, unordered_set<int>& solution, unsigned int& k);


#endif //VERTEX_COVER_H

0 个答案:

没有答案