0

I'm using C++ templates and encounter the following issue.

I try to use class ImplG's method func in class ImplM, however the linker reports an error.

user:/home/test/build# make
Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/main.cc.o
[100%] Linking CXX executable main
/usr/bin/ld: CMakeFiles/main.dir/main.cc.o:(.data.rel.ro._ZTV9GatheringI9ImplState9ImplRouteE[_ZTV9GatheringI9ImplState9ImplRouteE]+0x10): undefined reference to `Gathering<ImplState, ImplRoute>::gather(ImplState const&)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/main.dir/build.make:84: main] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
# CMakeLists.txt
ADD_EXECUTABLE(main
        main.cc
)
// mctsimpl.hpp
#include <vector>

class State {
};

template <class T>
class Action {
    void execute(T&);
};

template <class A>
class Route {
public:
    std::vector<A> actions;

    A getAction();
};

template <class T, class R>
class Gathering {
public:
    virtual R gather(const T&);
};

// Actually this is a MCTS implementation
// But those search methods are omitted here
// I just need to collect some actions
template<class T, class A, class R>
class MCTS {
public:
    MCTS(T& rootData, Gathering<T, R>* gathering) :
        state(rootData),
        gathering(gathering) {
    }

    R gather() {
        return gathering->gather(state);
    }
private:
    Gathering<T, R>* gathering;
    T& state;
};

// mctslib.hpp
#include "mctsimpl.hpp"

class ImplAction;

class ImplRoute;

class ImplState : public State {
public:
    ImplState() :
        i(0) {
    }

    int i;
    std::vector<ImplAction> actions;

    void execute(int i);

    ImplRoute gather() const;
};

class ImplAction : Action<ImplState> {
public:
    ImplAction(int i) :
        i(i) {
    };

    int i;

    void execute(ImplState& state) {
        state.execute(i);
    }
};

class ImplRoute : public Route<ImplAction>{
public:
    ImplRoute(std::vector<ImplAction> actions) :
        actions(actions) {
    }

    ImplAction getAction() {
        return actions[0];
    }

    std::vector<ImplAction> actions;
};

class ImplGathering : public Gathering<ImplState, ImplRoute>{
public:
    ImplGathering() {}

    ImplRoute gather(const ImplState& s) override {
        return s.gather();
    }
};

using ImplMCTS = MCTS<ImplState, ImplAction, ImplRoute>;
// mcts.hpp
#include "mctslib.hpp"

void ImplState::execute(int i) {
    actions.push_back(ImplAction(i));
    this->i = i;
}

ImplRoute ImplState::gather() const {
    return ImplRoute(actions);
}
// main.cc
#include "mcts.hpp"

int main() {
    ImplState state;
    ImplGathering* gathering = new ImplGathering();
    ImplMCTS mcts(state, gathering);

    ImplAction action(1);
    action.execute(state);
    action.execute(state);
    action.execute(state);

    // Use here
    mcts.gather();
}

Now I provide my simplified code and add the linking error.

fields1631
  • 21
  • 4
  • 1
    please create a [MRE] - emphasis on **reproductible**. With your current code I get *different* errors, like "returning incomplete type `ImplR`" and "wrong number of arguments to `M`" – bolov Aug 21 '21 at 03:58
  • 2
    The linker said that it cannot find the definition of `G<>::func()` for certain template arguments. I'm at a loss to find it also. Could you point out where in your code is the function's definition? (Not the definition in a derived class, but the one for the base class.) – JaMiT Aug 21 '21 at 03:58
  • Does this answer your question? [Why do I get "unresolved external symbol" errors when using templates?](https://stackoverflow.com/questions/456713/why-do-i-get-unresolved-external-symbol-errors-when-using-templates) – Ken White Aug 21 '21 at 04:05
  • @bolov Thank, I'll provide an example soon – fields1631 Aug 21 '21 at 04:08
  • Also, `M<>` takes only 2 template arguments, but the `using ImplM` statement is passing 3 arguments. This should not even compile. – Remy Lebeau Aug 21 '21 at 04:52
  • @RemyLebeau Thanks for your reply, I have correct that code. – fields1631 Aug 21 '21 at 05:07
  • 1
    You have added several missing pieces, which is good and fits into the "reproducible" aspect of a [mre]. However, you still have work to do on the "minimal" aspect. For example, does the error disappear if you reduce the definition of `ImplState` down to `class ImplState {};` and eliminate the code that accesses members of `ImplState`? If the error is still present, then do this simplification. Repeat for each other class, until you are down to just what you need to reproduce the error in question. – JaMiT Aug 21 '21 at 05:11
  • @JaMiT The error is still present when I'm not accessing members of `ImplState` and just build and return a certain `ImplRoute` instance. However this solution is not valid to me even if it works. As I've hinted, this is a MCTS programme and it's necessary for me to access the members of states. – fields1631 Aug 21 '21 at 05:24
  • @fields1631 A [mre] (MRE) is not a solution for you. It is a debugging technique to isolate your issue. The idea is that you isolate your issue, get a solution in the simplified case, then apply that solution to your real case. The purpose of a MRE is to demonstrate your issue, **not your functionality**. In many respects, the less your MRE resembles your real code (due to abstract thinking), the better (because it makes it easier for others to help you, and easier for future readers to benefit from your question). – JaMiT Aug 21 '21 at 05:36

1 Answers1

0

Make your class abstract (by adding = 0), something like:

template <class T, class R>
class Gathering {
public:
    virtual R gather(const T&) = 0;
};
Top-Master
  • 7,611
  • 5
  • 39
  • 71