链接错误"LNK2019:未解决的外部符号"没有外部库 [英] Linking error "LNK2019: unresolved external symbol" without external libraries

查看:86
本文介绍了链接错误"LNK2019:未解决的外部符号"没有外部库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在处理一个稍大的项目时,我似乎在链接器上遇到问题.(我使用的是Visual Studios2019.我试图从Lubos Briedas的"Plasma Simulation by Example"(示例等离子体仿真)中重新创建代码,尽管存在大部分错误,但是对于C ++模拟,它中的大多数内容都很好,但本书中存在一些错误.)

I've seem to be having problems with the linker while working on a slightly bigger project. (I'm using Visual Studios 2019. I'm trying to recreate code from Lubos Briedas "Plasma Simulation by Example" and there are some mistakes in the book, even though most of it is fine a great introduction into simulations with C++.)

目前,我收到以下错误消息:

Currently I receive the following errors:

Output.obj : 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 Field_<double> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Field_@N@@@Z) referenced in function "void __cdecl Output::fields(class World &,class std::vector<class Species,class std::allocator<class Species> > &)" (?fields@Output@@YAXAAVWorld@@AAV?$vector@VSpecies@@V?$allocator@VSpecies@@@std@@@std@@@Z)
Output.obj : 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 Field_<struct vec3<double> > &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Field_@U?$vec3@N@@@@@Z) referenced in function "void __cdecl Output::fields(class World &,class std::vector<class Species,class std::allocator<class Species> > &)" (?fields@Output@@YAXAAVWorld@@AAV?$vector@VSpecies@@V?$allocator@VSpecies@@@std@@@std@@@Z)
Species.obj : error LNK2019: unresolved external symbol "public: void __thiscall Field_<double>::scatter(struct vec3<double>,double)" (?scatter@?$Field_@N@@QAEXU?$vec3@N@@N@Z) referenced in function "public: void __thiscall Species::computeNumberDensity(void)" (?computeNumberDensity@Species@@QAEXXZ)

我已经多次检查了消息中提到的功能的拼写,还检查了是否没有其他定义.我还查看了是否可以在类之外(如代码中)完成 operator<< -overloading,这似乎很好.向错误消息中的函数添加 const 不能解决它们,因此我认为这与l/rvaulues无关.我发现此错误的大多数其他解决方案包括通过属性页向链接器添加某些内容,但是由于我不包括任何特殊的外部库,因此我不知道该在其中添加什么以及是否需要添加某些内容.全部添加.

I've checked the spelling of the functions mentioned in the messages multiple times and also checked that there is no additional definition. I also looked up whether the operator<<-overloading can be done outside of a class (like in the code) and it seems to be fine. Adding const to the functions in the error messages don't solve them, so I don't think it has something to do with l/rvaulues. Most other solutions to this error I've found included adding something to the linker via the property pages, but since I don't include any special external library, I don't know what I would have to add there and if something needs to be added all.

还有其他可能导致此错误的可能性吗?以及如何检测和解决需要添加或更改的内容?我已经被困了很长时间了,希望你们中的一个能够帮助我.

Are there any other possibilities which might lead to this error? And how can I detect and solve what needs to be added or changed? I've been stuck for quite some time now and hope one of you might be able to help me.

(如果需要,我可以提供完整的代码,但是我现在不提供它,因为我没有一个最小的工作示例,而且如果没有这个示例,可能会太多.)

(If needed, I can provide the complete code, but I refrain from it for now, because I don't have a minimal working example and it might be to much without.)

以下是错误消息中提到的功能的代码:

Here is the code for the functions mentioned in the error messages:

// Output.h
#pragma once
#include <sstream>
#include <fstream>
#include <ostream>
#include <iostream>

#include "Fields_.h"
#include "World.h"
#include "Species.h"

namespace Output { void fields(World& world, std::vector<Species> &species); }
           
void Output::fields(World& world, std::vector<Species> &species);

// Output.cpp
#include "Output.h"

// write data to a file stream
template<typename T>
std::ostream& operator<<(std::ostream& out, Field_<T>& f) {
    for (int k = 0; k < f.nk; k++, out << "\n") // new line after each "k"
        for (int j = 0; j < f.nj; j++)
            for (int i = 0; i < f.ni; i++)
                out << f.data[i][j][k] << " ";
    return out;
}

// saves output in VTK format
void Output::fields(World& world, std::vector<Species>& species) {
    std::stringstream name;     // build file name
    name << "fields.vti";   // here we just set it to a given string

    // open output file
    std::ofstream out(name.str());
    if(!out.is_open()) { std::cerr << "Coulld not open " << name.str() << std::endl; return; }

    // ImageData is a VTK format for structured Cartesian meshes
    out << "<VTKFile type=\"ImageData\">\n";
    double3 x0 = world.getX0();
    double3 dh = world.getDh();
    out << "<ImageData Origin=\"" << x0[0] << " " << x0[1] << " " << x0[2] << "\" ";
    out << "Spacing=\"" << dh[0] << " " << dh[1] << " " << dh[2] << "\" ";
    out << "WholeExtent=\"0 " << world.ni - 1 << " 0 " << world.nj - 1 << " 0 " << world.nk - 1 << "\">\n";

    // output data stored on nodes (point data)
    out << "<PointData>\n";

    // node volumes, scalar
    out << "<DataArray Name=\"NodeVol\" NumberOfComponents=\"1\" format=\"ascii\" type=\"Float64\">\n";
    out << world.node_vol;  // use the overloaded << operator
    out << "</DataArray>\n";

    // potential, scalar
    out << "<DataArray Name=\"phi\" NumberOfComponents=\"1\" format=\"ascii\" type=\"Float64\">\n";
    out << world.phi;   // use the overloaded << operator
    out << "</DataArray>\n";
    /*  */  // output world.phi

    // charge density, scalar
    out << "<DataArray Name=\"rho\" NumberOfComponents=\"1\" format=\"ascii\" type=\"Float64\">\n";
    out << world.rho;   // use the overloaded << operator
    out << "</DataArray>\n";
    /*  */  // output world.rho

    // electric field, 3 component vector
    out << "<DataArray Name=\"ef\" NumberOfComponents=\"3\" format=\"ascii\" type=\"Float64\">\n";
    out << world.ef;    // uses overloaded << from Field_ and vec3
    out << "</DataArray>\n";

    // close the tags
    out << "</PointData>\n";
    out << "</ImageData>\n";
    out << "</VTKFile>\n";

    // species number densities
    for (Species& sp : species) {
        out << "<DataArray Name=\"nd." << sp.name << "\" NumberOfComponents=\"1\" format=\"ascii\" type=\"Float64\">\n";
        out << sp.den;
        out << "</DataArray>\n";
    }
}       // file closed here as 'out'  goes out of scope

将带有错误的函数从.cpp移动到.h中的类,解决了一个错误.但这对于其他错误是不可能的,因为必须进行分类才能将其放入.

Moving the function with the error from the .cpp to the class in .h solved one error. But this isn't possible with the other errors, since there is to class to put them in.

// Fields_.h
#pragma once
#include <ostream>
//#include <utility>
#include "vec3.h"

template <typename T>
class Field_{
public:
    
    // constructor
    Field_(int ni, int nj, int nk) : ni{ ni }, nj{ nj }, nk{ nk }{
        data = new T * *[ni];           // ni pointers to pointers of type T
        for (int i = 0; i < ni; i++) {
            data[i] = new T * [nj];     // allocte nj pointers to T
            for (int j = 0; j < nj; j++)
                data[i][j] = new T[nk]; // allocate nk objects of type T
        }
        // when creating a scalar Field (not Field_<double3>), initialization has to be done explicitly
        if (!std::is_same<T, double3>::value) {
            operator=(0);
        }
        //operator=(0); // call the overloaded operator= function
        //(*this) = 0;                  // clear data (doesn't work)
    }

    // destructor, frees momory in reverse order
    ~Field_() {
        if (data == nullptr) return;        // return if unallocated
        for (int i = 0; i < ni; i++) {      // release memory in reverse order
            for (int j = 0; j < nj; j++)
                delete data[i][j];
            delete data[i];
        }

        delete[] data;
        data = nullptr;                     // mark as free
    }

    // data acces operator
    T** operator[] (int i) { return data[i]; }

    // overload the assignment operator
    Field_<T>& operator= (const T s) {
        for (int i = 0; i < ni; i++)
            for (int j = 0; j < nj; j++)
                for (int k = 0; k < nk; k++)
                    data[i][j][k] = s;
        return *this;                           // return refernce to self
    }

    // copy constructor
    Field_(const Field_& other) :
        Field_{ other.ni,other.nj, other.nk } {
        for (int i = 0; i < ni; i++)
            for (int j = 0; j < nj; j++)
                for (int k = 0; k < nk; k++)
                    data[i][j][k] = other(i, j, k);
        }

    // move construtor
    Field_(Field_ &&other) noexcept:
        ni{ other.ni }, nj{ other.nj }, nk{ other.nk } {
            if (data) this->~Field_();  // deallocate own data /*doesn't work??? why is it needed?*/
            data = other.data;      // steal the data
            other.data = nullptr;   // invalidate
        }

    // move assignment operator
    Field_& operator=(Field_&& f) {
        if (data) ~Field_();    // deallocate own data
        data = f.data; f.data = nullptr; return *this;
    }

    // read-only acces to data[i][j][k]
    T operator() (int i, int j, int k) const { return data[i][j][k]; }

    void operator /=(const Field_& other) {
        for (int i = 0; i < ni; i++)
            for (int j = 0; j < nj; j++)
                for (int k = 0; k < nk; k++) {
                    if (other.data[i][j][k] != 0)
                        data[i][j][k] /= other(i, j, k); // in the book data[i][j][k] /= other[i][j][k];
                    else
                        data[i][j][k] = 0;
                }
    }

    Field_& operator += (const Field_& other) {
        for (int i = 0; i < ni; i++)
            for (int j = 0; j < nj; j++)
                for (int k = 0; k < nk; k++)
                    data[i][j][k] += other(i, j, k);
        return (*this);
    }

    // compound multiplication
    Field_& operator *= (double s) {
        for (int i = 0; i < ni; i++)
            for (int j = 0; j < nj; j++)
                for (int k = 0; k < nk; k++)
                    data[i][j][k] *= s;
        return (*this);
    }

    // multiplikation operator, returns new Field set to f*s
    friend Field_<T> operator*(double s, const Field_<T>& f) {
        Field_<T> r(f);
        return std::move(r *= s);   // force move
        //return move(r *= s);  // force move
        //return r;
        //return r *= s;
    }

    void scatter(double3 lc, double value) {
        // make sure we are in domain
        if (lc[0]<0 || lc[0]>ni - 1 || lc[1]<0 || lc[1]>nj - 1 || lc[2]<0 || lc[2]>nk - 1) return;

        // compute the cell index and the fractional distances
        int i = (int)lc[0];
        double di = lc[0] - i;
        int j = (int)lc[1];
        double dj = lc[1] - j;
        int k = (int)lc[2];
        double dk = lc[2] - k;

        // deposit fractional values to the 8 surrounding nodes
        data[i][j][k] += value * (1 - di) * (1 - dj) * (1 - dk);
        data[i + 1][j][k] += value * (di) * (1 - dj) * (1 - dk);
        data[i + 1][j + 1][k] += value * (di) * (dj) * (1 - dk);
        data[i][j + 1][k] += value * (1 - di) * (dj) * (1 - dk);
        data[i][j][k + 1] += value * (1 - di) * (1 - dj) * (dk);
        data[i + 1][j][k + 1] += value * (di) * (1 - dj) * (dk);
        data[i + 1][j + 1][k + 1] += value * (di) * (dj) * (dk);
        data[i][j + 1][k + 1] += value * (1 - di) * (dj) * (dk);
    }

    friend std::ostream& operator<<(std::ostream& out, Field_<T>& f); // so data can be protected member of Field_

    const int ni, nj, nk;   // number of nodes

protected:
    T*** data;  // pointer of type T
};

template<typename T>
// output
std::ostream& operator<<(std::ostream& out, vec3<T>& v) {
    out << v[0] << " " << v[1] << " " << v[2];
    return out;
}


using Field = Field_<double>;   // field of doubles
using FieldI = Field_<int>;     // field of integers
using Field3 = Field_<double3>; // vector field of doubles

// Fields_.cpp
#include "Fields_.h"

推荐答案

在Fields_类中添加 operator<< -重载(和 scatter 函数)解决了这些问题错误.现在还有其他问题,但这似乎已解决.

Adding operator<<-overloading (and the scatter function) into the Fields_ class solved these errors. Now there are others issues, but this seems to be fixed.

(@ john:也应该可以在类外定义模板.但是我不知道在这个例子中怎么做,这似乎足以满足我的需要.如果有人知道,更优雅的解决方法,我也很乐意尝试一下.)

(@john: It should be possible to define templates out of class as well. But I don't know how in this example and this seems to be sufficient for my needs. If anyone knows a more elegant work around, I'm happy to try it out as well.)

这篇关于链接错误"LNK2019:未解决的外部符号"没有外部库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆