mardi 12 novembre 2019

Unresolved external symbol for one specific function on class template

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<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Individual<class std::valarray<int> >)" (??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.

Aucun commentaire:

Enregistrer un commentaire