-3

As the title states, I am getting the infamous unresolved external symbol linker issue.

I have already moved everything in the .h files. The template classes are no longer split between .h and .cpp files.

I have included them in the main file. I have triple-quadruple checked that the definition is there (obviously).

My files are as follows:

Utils.h:

Just a pretty cout for vector and valarray. Tested and working.

#pragma once

#include <vector>
#include <valarray>
#include <ostream>

using std::vector;
using std::valarray;
using std::ostream;


template <typename ValueType>
ostream& operator<< (ostream&, vector<ValueType>);

template <typename ValueType>
ostream& operator<< (ostream&, valarray<ValueType>);


template <typename ValueType>
ostream& operator<< (ostream& out, vector<ValueType> v)
{
    out << "Vec[";
    for (int i = 0; i < v.size() - 1; i++)
        out << v[i] << ", ";
    out << v[v.size() - 1] << "]";
    return out;
}


template <typename ValueType>
ostream& operator<< (ostream& out, valarray<ValueType> a)
{
    out << "VArr[";
    for (int i = 0; i < a.size() - 1; i++)
        out << a[i] << ", ";
    out << a[a.size() - 1] << "]";
    return out;
}

Fitness.h: A simple class with a couple valarrays and a bool. Implements a pretty-cout as well. Tested and working.

#pragma once

#include <valarray>
#include <ostream>

#include "Utils.h"

using std::valarray;
using std::ostream;


class Fitness {

public:
    class FitnessNotValidException : public std::exception {};
    class ValueIndexTooLargeException : public std::exception {};
    class IncorrectNewValuesLength : public std::exception {};

private:
    const valarray<double> weights;
    bool valid;
    valarray<double> values;

public:

    Fitness(const valarray<double>&);
    static Fitness max();
    static Fitness min();

    double WeightedFitness();

    const valarray<double>& Weights();

    bool Valid();
    void Valid(bool);

    void invalidate();
    void validate();

    const valarray<double>& Values();
    void Values(int, double);
    void Values(const valarray<double>&);

    double Value();
    void Value(double);

    friend ostream& operator<< (ostream&, Fitness);
};

// Implementation for everything...

ostream& operator<<(ostream & out, Fitness fit)
{
    out << "Fitness[W:" << fit.weights << ", V:" << fit.values << ", valid:" << fit.valid << "]";
    return out;
}

Individual.h: Template class having a Fitness member. Also implements the "pretty-cout".

#pragma once

#include <ostream>
#include <valarray>

#include "Fitness.h"

using std::ostream;


template <typename GeneType>
class Individual
{
private:
    Fitness fitness;
    GeneType genes;

public:

    Individual(Fitness, GeneType);

    Fitness& Fitness();

    GeneType& Genes();

    Individual<GeneType> copy();

    friend ostream& operator<< (ostream&, Individual<GeneType>);
};

// Implementation for everything...

template<typename GeneType>
ostream& operator<<(ostream& out, Individual<GeneType> ind)
{
    out << "Individual[G:" << ind.genes << ", F:" << ind.fitness << "]";
    return out;
}

All these 3 files are included, in the same order, in the main file. If I try to print the genes and fitness of an individual all is well:

Individual<valarray<int>> ind = ind_builder.build();

cout << ind.Fitness() << endl << ind.Genes() << endl;

/*
Fitness[W:VArr[1], V:VArr[0], valid:0]
VArr[0, 0, 0, 1, 0, 1, 1, 1, 0, 1]
*/

Meaning the << for valarray, Fitness works, so I did not get anything wrong in the concept of how << should work. But when I try: cout << ind << endl;

error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream

&,class Individual >)" (??6@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV01@V?$Individual@V?$valarray@H@std@@@@@Z) referenced in function main

I don't see where the issue is. The includes seem to be in order and there is no splitting problem between .h and .cpp. Is there another template gotcha that I should have known? Because I have been searching for a few days for a solution aside from the ones always recommended (like moving all the code into the .h file) with no success.

yaodav
  • 1,126
  • 12
  • 34
Rares Dima
  • 1,575
  • 1
  • 15
  • 38
  • What is `ind_builder` ? Hint: you will get better responses if you can provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – Anubis Nov 12 '19 at 14:18

1 Answers1

5

operator << definition does not match operator << friend declaration, notice that operator << defined is actually a template and therefore will be less preferred than non-implemented non-template friend. So you are getting linker error because compiler inserted invocation of non-template non-implemented friend function. Also operator << should take object by const-qualified reference.

You should avoid friend, but if you still going to use it declaration should be

template <typename GeneType>
class Individual;

template<typename GeneType>
ostream & operator <<(ostream &, Individual<GeneType> const & individual);

template <typename GeneType>
class Individual
{
   template<typename GeneTypeInner>
   friend ostream & operator <<(ostream &, Individual<GeneTypeInner> const & individual);
};

template<typename GeneType>
ostream & operator<<(ostream& out, Individual<GeneType> const & individual)
{
    out << "Individual[G:" << individual.genes << ", F:" << individual.fitness << "]";
    return out;
}
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • 1
    In addition, for those who want very elaborate information on how to use friend in template classes: https://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class – Aziuth Nov 12 '19 at 14:28
  • Holy f... that... makes sense when explained, especially with the link in @Aziuth 's comment but that seems so convoluted and unnecessary. Thank you! Is there a kind of naming convention for these extra templates that exist only to satisfy the compiler/linker? – Rares Dima Nov 12 '19 at 14:40