0

I am trying to write a series of classes under a namespace titled numc using the C++17 compiler. Currently I am working on a root solver class and for some reason when I define the functions in the header file the code works just fine; however, when I define the functions in the .cpp file, the code fails on compilation with the error clang: error: linker command failed with exit code 1

If I define the .hpp file like so with the .cpp file shown it works fine.

 // Working main.cpp file
 double upper = 3.0;
 double lower = 0.0;
 double guess = 2.0;
 double right_side = 0.0;
 double result;
 result = numc::RootSolver::bisect(upper, lower, right_side, guess, func1);

double func1(double x)
{
    return pow(x, 6.0) - x - 1.0;
}

// Working numc.hpp file
namespace numc
{
    class RootSolver
    {
    public:
        static double
        bisect(double upper, double lower, double right_side, 
               double guess, const std::function<double(double)>& func,
               double uncertainty = 0.001, int iter = 150);
    private:
        [[noreturn]] static void exit_program(int iter);
    }
// ================================================================
// ================================================================
double
    RootSolver::bisect(double upper, double lower, double right_side, 
                       double guess, const std::function<double(double)>& func
                       double uncertainty, int iter)
    {
        for (int i = 0; i < iter; i++)
        {
            if (func(guess) - right_side <= unc and
                func(guess) - right_side >= -unc) return guess;
            else if (func(guess) - right_side > unc)
            {
                upper = guess;
            }
            else lower = guess;
            guess = lower + (upper - lower) / 2.0;
        }
        RootSolver::exit_program(iter);
    }
// ================================================================
// ================================================================
    [[noreturn]] void
    RootSolver::exit_program(int iter)
    {
        std::string one("Function did not converge within ");
        std::string two(" iterations");
        std::cout << one << iter << two << std::endl;
        exit (EXIT_FAILURE);
    }
}

When define in the manner shown above the program works just fine and produces a result of 1.3477. However, as you can see, instead of just defining the function prototypes in the .hpp file, I also defined the functions, which is bad form. The functions should be defined in the numc.cpp file.

If I take the working .hpp file shown above and rewrite it as such and place the function definition in the .cpp file I arrive at the following code.

// numc.hpp code
namespace numc
{
    class RootSolver
    {
    public:
        static double
        bisect(double upper, double lower, double right_side, 
               double guess, const std::function<double(double)>& func,
               double uncertainty = 0.001, int iter = 150);
    private:
        [[noreturn]] static void exit_program(int iter);
    }
}

and the numc.cpp code

#include "numc.hpp"
double
numc::RootSolver::bisect(double upper, double lower, 
                         double right_side, double guess, 
                         const std::function<double(double)>& func,
                         double unc, int iter)
{
    for (int i = 0; i < iter; i++)
    {
        if (func(guess) - right_side <= unc and
            func(guess) - right_side >= -unc) return guess;
        else if (func(guess) - right_side > unc)
        {
            upper = guess;
        }
        else lower = guess;
        guess = lower + (upper - lower) / 2.0;
    }
    numc::RootSolver::exit_program(iter);
}
// ================================================================
// RootSolver PRIVATE MEMBER-FUNCTIONS

[[noreturn]] void
numc::RootSolver::exit_program(int iter)
{
    std::string one("Function did not converge within ");
    std::string two(" iterations");
    std::cout << one << iter << two << std::endl;
    exit (EXIT_FAILURE);
}

I have tried several variations, but no matter how I do it, when I place the member function definitions in the .numc.cpp file, the code fails on compilation and tells me that I have a linker issue. If anyone can point out my mistake I would greatly appreciate it.

Jon
  • 1,621
  • 5
  • 23
  • 46
  • I don't see the problem but for simplicity, use `namespace numc { ... }` around your definitions too. – Ted Lyngmo May 30 '19 at 17:07
  • I tried that and it did not work either – Jon May 30 '19 at 17:11
  • @Jon How does your linker command line look? Are you linking to the compiled results of `numc.cpp` at all? – πάντα ῥεῖ May 30 '19 at 17:13
  • yes, my command line is `clang++ -std=c++17 -stdlib=libc++ -Wall main.cpp numc.cpp` – Jon May 30 '19 at 17:14
  • @Jon Ok, but it's a step in the right direction. Keep it like that. What is the exact error you get when having the surrounding `namespace` in the `.cpp` file? – Ted Lyngmo May 30 '19 at 17:15
  • Its the exact same error, whether I define the member functions in the `numc.cpp` file as `numc::class::function` or namespace numc{} with the function calls in the parenthesis. – Jon May 30 '19 at 17:17
  • `clang: error: linker command failed with exit code 1` is not the actual error. – Ted Lyngmo May 30 '19 at 17:18
  • 1
    @Jon You're missing a `;` after the class definition in the header file BTW. – πάντα ῥεῖ May 30 '19 at 17:18
  • Good catch - and that is the case in the working code too. Turn on stricter rules for your compiler. Btw, why `-stdlib=libc++` ? `clang++` is usuallly enough. – Ted Lyngmo May 30 '19 at 17:21
  • Unfortunately that is not the issue, that was just an artifact of me manually re-writing the example to stack overflow. That `;` is present in the actual code. I may take an hour break and come back to this. Maybe I need to re-install the compiler? – Jon May 30 '19 at 17:26
  • @Ted Lyngmo, I am using a clang compiler on a Mac with Xcode. The clang compiler usually defaults to libstdc++ owhich is the GNU standard, but does not have all required functionality for C++11 support and later versions. – Jon May 30 '19 at 17:28
  • That sounds like an odd setup. C++11 is old news and if that setup is blocking the actual error that the linker gives you, compile it manuallly to catch what it actually says. That should make the problem fairly obvious.- – Ted Lyngmo May 30 '19 at 17:30

0 Answers0