0

Almost done this program, and after moving to a public computer, and changing some code, I noticed that I'm receiving a linker error, and I also decided to ask about another error (and why it's happening).

The function in question is below. For some reason, the last line "ValidTlds[transferString]...." shows that VS doesn't recognize ValidTLDs, and will only do so when I add TldPart:: (the name of the file it's in) behind it. Is this a name conflict with something else?

Also, the more important error I believe also deals with function is the unresolved external symbol. The exact line:

Error   3   error LNK2001: unresolved external symbol "public: static class std::map<class String,class String,struct std::less<class String>,class std::allocator<struct std::pair<class String const ,class String> > > TldPart::ValidTlds" (?ValidTlds@TldPart@@2V?$map@VString@@V1@U?$less@VString@@@std@@V?$allocator@U?$pair@$$CBVString@@V1@@std@@@3@@std@@A)    V:\My Documents\Visual Studio 2010\Projects\EmailChecker_HW2\EmailChecker_HW2\TldPart.obj

I tried to read the Q&A page you had on external symbols, and tried a few suggestions (originally I had two), and I managed to reduce it to one linker error I believe by declaring the static function outside of the class. You guys see what's wrong? In the main.cpp, I referenced the function as `TldPart::PreloadTLDs;', but removing that line didn't remove the error (and I have #include "TldPart.h" at the top of the main.cpp file). Here's the function, I'll post the header and cpp file underneath for full reference. The full project is pretty extensive (close to 1100 lines last I checked), so I only included these for starters. Thanks for the help, I appreciate it.

static void PreloadTLDs()

static void PreloadTLDs()
{
    bool initialized = false;
    bool fileStatus = false;
    string tldTest = ""; // used for getline() as allowed.
    char * transferString = " "; // used to transfer chars from string to String

    ifstream infile;

    infile.open("ValidTLDs.txt");

    fileStatus = infile.good();

    if(fileStatus != true)
        cout << "Cannot read ValidTLD's file. Please check your file paths and try again.";
    else
    {
        while(!infile.eof())
        {
            getline (infile, tldTest); // sets the current TLD in the list to a string for comparision

            // converts TLD to lowercase for comparison.
            for(unsigned int x = 0; x<tldTest.length(); x++)
            {
                tldTest[x] = tolower(tldTest[x]);
                transferString[x] = tldTest[x];

                ValidTlds[transferString] = String(transferString);
            }
        }
    }
}

main.cpp (shortened)

#include <iostream>
#include <fstream>
#include "String.h"
#include <map>
#include <string> // used for the allowed getline command
#include "Email.h"
#include "TldPart.h"

using namespace std;

void main()
{
    string getlinetransfer; // helps transfer email from getline to c string to custom String
    double emailTotal = 0.0; // Used to provide a cool progress counter
    double emailCounter = 0.0; // Keeps track of how many emails have been verified.
    int x = 0; // used to set c-string values, counter for loop
    char * emailAddress = new char[getlinetransfer.size() + 1]; // c string used for getting info from getline.

    cout << "Welcome to email validation program!" << endl;
    cout << "Pre-Loading Valid TLD's..... \n" << endl;

    TldPart::PreloadTLDs;
}

TldPart.h

// TldPart.h - TldPart validation class declaration
// Written by ------

#pragma once

#include "String.h"
#include <map>
#include "SubdomainPart.h"
#include <string>
#include <fstream>
#include <iostream>

using namespace std;



class TldPart
{
public:
    // MUST HAVE a defualt constructor (because TldPart is a member of Domain)
    TldPart() {}

    // Takes the address and stores into the Address data member
    void Set(const String& address);

    static void PreloadTLDs();

    // Returns true when the Address is valid or false otherwise
    bool IsValid();

    static map<String, String> ValidTlds;
private:
    String Address; 
};

TldPart.cpp

// TldPart.cpp - TldPart validation class implementation
// Written by Max I. Fomitchev-Zamilov

#pragma once

#include "TldPart.h"
using namespace std;

void TldPart()
{

}

// Takes the address and stores into the Address data member
void TldPart::Set(const String& address)
{
    Address = address;
}

static void PreloadTLDs()
{
    bool initialized = false;
    bool fileStatus = false;
    string tldTest = ""; // used for getline() as allowed.
    char * transferString = " "; // used to transfer chars from string to String

    ifstream infile;

    infile.open("ValidTLDs.txt");

    fileStatus = infile.good();

    if(fileStatus != true)
        cout << "Cannot read ValidTLD's file. Please check your file paths and try again.";
    else
    {
        while(!infile.eof())
        {
            getline (infile, tldTest); // sets the current TLD in the list to a string for comparision

            // converts TLD to lowercase for comparison.
            for(unsigned int x = 0; x<tldTest.length(); x++)
            {
                tldTest[x] = tolower(tldTest[x]);
                transferString[x] = tldTest[x];

                ValidTlds[transferString] = String(transferString);
            }
        }
    }
}

// Returns true when the Address is valid or false otherwise
bool TldPart::IsValid()
{   
    bool tldFound = false;

    map<String, String>::iterator it;

    String TLDMatch;

    TLDMatch = TldPart::ValidTlds.find(Address)->first;
    it = TldPart::ValidTlds.find(Address);

    if(it == ValidTlds.end())
        tldFound == false;
    else
        tldFound == true;

    return tldFound;
}
Reciever80
  • 105
  • 1
  • 1
  • 10

1 Answers1

2

This code promises that a single static variable TldPart::ValidTlds will be defined somewhere.

class TldPart
{
    static map<String, String> ValidTlds;
};

Add this to TldPart.cpp and you'll be good.

#include "TldPart.h"
using namespace std;

map<String, String> TldPart::ValidTlds;  // DECLARE YOUR STATIC VARIABLE

void TldPart()
{

}
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • Awesome, that helped with the weird namespace issue for the map STL. Any idea on the unresolved external error? – Reciever80 Mar 13 '13 at 03:15
  • Where should I place it in the cpp file? There's three functions, a default constructor, or as a global. – Reciever80 Mar 13 '13 at 03:17
  • It still gives me the 2001 linker error with 1 unresolved external. Does it have to do with the fact it's static, perhaps? – Reciever80 Mar 13 '13 at 03:30
  • I have one for validtlds, like before, and if I change TldPart::PreloadTlds; to TldPart::PreloadTlds() it shows that there's a second unresolved external 2019 error for what looks like the preload function itself as referenced in main. Can post exact error after class. – Reciever80 Mar 13 '13 at 16:15
  • @Reciever80 it sounds like you're building wrong. If nothing defined in `TldPart.cpp` can ever be used, it's either not getting compiled, or not getting linked. – Drew Dormann Mar 13 '13 at 17:21
  • Found out what went wrong. Before you posted the second half of that code, I had placed that line in the function itself and never deleted it (I had written it last night), and after deleting it, placing the code in the global area worked. Thanks! For anyone reading this in the future, to solve the issue with the static function, I was calling it in the main as `TldPart::PreloadTlds();` since I wanted it to run once. Since it's a map, I was able to delete the call in main.cpp, and add to the TldPart::IsValid() function `if(ValidTlds.empty()){ this->PreloadTlds();}` – Reciever80 Mar 13 '13 at 17:41