0

I'm attempting to write a class that solves a system of nonlinear equations (a root finder). For this, I've written a class that encapsulates all the internal functions needed, as well as the system to solve: a function that takes an Eigen vector and returns an Eigen. The public newt member function takes an Eigen vector (the initial guess), runs the algorithm with that initial guess, and returns the Eigen vector r such that func(r) = {0, 0, ..., 0}. I've written the functions as prescribed here: writing template functions that take instantiations of MatrixBase.

The way I've handled taking an arbitrary function to solve was to implement a base class and then have the user extend it, defining func, the function to solve. The class I have is

class Newt {
private:
    template<typename TR, typename T1, typename T2, typename T3>
    tuple<TR,bool> lnsrch(const MatrixBase<T1> &xold, const double fold, const MatrixBase<T2> &g, MatrixBase<T3> &p, const double stepmax);

    template <typename TR, typename T1, typename T2>
    TR fdjac(const MatrixBase<T1> &x, const MatrixBase<T2> &fvec);

public:
    template <typename TR, typename T1>
    TR func(const MatrixBase<T1>&);

    template <typename TR, typename T1>
    tuple<TR,bool> newt(const MatrixBase<T1> &xx);
};

The user then inherits from Newt and overrides the func method to the desired function to solve:

struct NewtD : public Newt
{
    template <typename T1, typename T2>
    T1 func(const MatrixBase<T2> &z) {
        // Content
    }   
};

Then he instantiates it and calls the newt member function. However, when I compile this with the following test case:

struct Newt3 : public Newt
{
    template <typename T1, typename T2>
    T1 func(const MatrixBase<T2> &x) {
        return (Vectord<3>() << 
            z(0),
            z(1)*z(2),
            pow(z(2)-1,2)
        ).finished();
    }   
};

int main() {
    Newt3 solver3;
    bool check;
    tie(X,check) = solver3.newt<Vectord<3>>(X);
}

I get the following linker error, when compiling with g++ 6.2.0

undefined reference to `std::tuple<Eigen::Matrix<double, 3, 1, 0, 3, 1>, bool> Newt::newt<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&)'

It seems it can't find newt? I have no idea why this is, the signature in the error seems to match my code, everything seems okay. Any idea how to solve this?

PS: Oh yeah, I forgot: Vectord<N> is a shortcut template type simply defined as

template<size_t N>
using Vectord = Matrix<double, N, 1, 0>;

PPS: The implementation is in a separate file. I didn't include it because it's quite big, but bottom-line is every function is defined there, including Newt::newt

template <typename TR, typename T1>
tuple<TR,bool> Newt::newt(const MatrixBase<T1> &xx) {
    // Body
}
andrepd
  • 587
  • 6
  • 20
  • `Newt::newt` doesn't appear to be implemented. It's certainly absent from the code you've shown here. Apparently, it's absent from the code you've shown to the compiler, too. – Igor Tandetnik Nov 12 '16 at 23:57
  • No, it's implemented in the `.cpp`. I didn't include it because it is quite long. I will add the skeleton to the question for clarity. – andrepd Nov 12 '16 at 23:58
  • 1
    Templates must be implemented in the header. The definition has to be visible to the compiler at the point where the template is used and its parameters become known. – Igor Tandetnik Nov 13 '16 at 00:01
  • How so? You mean if I have a class template I cannot split the declaration (`.h`) and the implementation (`.cpp`) into two files? I didn't know of that. – andrepd Nov 13 '16 at 00:05
  • 1
    Today you learned. See also: http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – Igor Tandetnik Nov 13 '16 at 00:06
  • Thank you, I had no idea that was the case. I would never have thought of that. However this is very impractical. Not only do I have to forgo separating between a declaration file and a definition file, I will end up having to put *everything* in the same file, since `Newt3::func` will end up, in my use case, depending on other functions such as a gaussian integrator. This would mean I would have to put everything: declaration, definition, derived class, `func` declaration, and everything `func` might depend on, on the same file. That is highly impractical. – andrepd Nov 13 '16 at 00:38
  • Welcome to C++. If a compiler cannot read the definition of a template, it cannot generate the code, resulting in undefined references. I don't have the exact percentages, but I wouldn't be surprised if more than half of the C++ library code consists of templates defined in the header files. Everything in `` is a header file. Everything in various container header files is a template, etc... – Sam Varshavchik Nov 13 '16 at 00:42
  • It makes sense. The answer @Igor linked cleared things up for me. How do you deal with dependency problems, though? Say my `func` depends on something else. I have to bring everything into the same file? – andrepd Nov 13 '16 at 00:52
  • @andrepd: Do keep in mind that headers can `#include` each other; so you don't need everything to literally be in the same file, just in the same translation unit. And if your templates depend on any *non*-template functions, then those non-template functions can still be *defined* in .cpp files, as long as they're *declared* in .h files (and not defined as static/inline/whatnot). – ruakh Nov 13 '16 at 01:32

0 Answers0