微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

没有外部库的链接错误“LNK2019:未解析的外部符号”

如何解决没有外部库的链接错误“LNK2019:未解析的外部符号”

我在处理一个稍大的项目时似乎遇到了链接器问题。 (我正在使用 Visual Studios 2019。我正在尝试重新创建 Lubos Briedas “plasma Simulation by Example”中的代码,书中有一些错误,尽管其中大部分内容都很好,是对 C++ 模拟的很好的介绍。)

目前我收到以下错误

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,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::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<< 重载是否可以在类之外完成(如代码中),似乎没问题。将 const 添加错误消息中的函数并不能解决它们,所以我认为它与 l/rvaulues 无关。我发现此错误的大多数其他解决方包括通过属性页向链接添加一些内容,但由于我不包含任何特殊的外部库,我不知道我必须在那里添加什么以及是否需要添加某些内容全部添加

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

(如果需要,我可以提供完整的代码,但我暂时不提供,因为我没有最小的工作示例,而且可能没有太多。)

这是错误消息中提到的函数代码

// 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 中的类解决一个错误。但这对于其他错误来说是不可能的,因为需要上课才能将它们放入。

// 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,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,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 函数)解决了这些错误。现在还有其他问题,但这似乎已解决。

(@john:也应该可以在课外定义模板。但我不知道在这个例子中如何,这似乎足以满足我的需要。如果有人知道一个更优雅的工作,我也很乐意尝试一下。)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?