0

So, I'm having an issue with linking. The answer is probably dead-weight easy, but I guess I'm bonked. I define a class for calculating things that takes a stringstream.

Relevant section of header file:

#include <sstream>
using namespace std;
template<class T>
class Finder {
public:
    Finder(istringstream& input) {};
    ~Finder() {};

    template<typename T> Finder(T& input) {};
    template<typename T> ~Finder() {};

    T check(istringstream&);

    template<typename T> friend ostream& operator << (ostream&, Finder<t>&);
};

template<class T>
T Finder<T>::check(istringstream& input)

And then my driver file to the last call:

#include <sstream>
#include <string>
#include <iostream>
#include "Finder.h"

using namespace std;

int main(int argc, char** argv) {
        Finder<int> thing;

        string expression;
            getline(cin, expression);

            while(expression[0] != 'q') {
        try {
            int result = thing.check(istringstream(expression));

Errors are: 1>driver.obj : error LNK2019: unresolved external symbol "public: __thiscall Finder::Finder(void)" (??0?$Finder@H@@QAE@XZ) referenced in function _main

1>driver.obj : error LNK2019: unresolved external symbol "public: __thiscall Finder::~Finder(void)" (??1?$Finder@H@@QAE@XZ) referenced in function __catch$_main$0

Hydra-
  • 1
  • 1
  • What is *that*: `~Finder(T)` Destructors don't have parameters. It should be `~Finder()` with no template arguments and no template parameter set. Or this: `Finder` in your stream inserter friend? Post *real* code please. And the *exact* error message verbatim is *always* a good idea. – WhozCraig May 03 '14 at 01:28
  • First, the error messages: 1>driver.obj : error LNK2019: unresolved external symbol "public: __thiscall Finder::Finder(void)" (??0?$Finder@H@@QAE@XZ) referenced in function _main 1>driver.obj : error LNK2019: unresolved external symbol "public: __thiscall Finder::~Finder(void)" (??1?$Finder@H@@QAE@XZ) referenced in function __catch$_main$0 – Hydra- May 03 '14 at 01:33
  • post the errors **in the question**. Also, `thing.check(istringstream(expression))` isn't valid standard C++. It may work if you're using a non-standard compiler extension (like VC++ has), but it isn't standard. – WhozCraig May 03 '14 at 01:35
  • So why do you have `template` in front of *either* the constructor or the destructor in this code? And does your compiler at least attempt to warn you that the inner template parameter `T` shadows the outer one? – WhozCraig May 03 '14 at 01:38
  • Sorry - new to this. Using VS2012 so the compilation shouldn't be an issue. Put the full text of the errors in the post and should have the rest of the code up in a minute... – Hydra- May 03 '14 at 01:39
  • sok. I think I know what you're *trying* to do. I'll post up an answer and if it helps all the better. If not, I'll drop it. – WhozCraig May 03 '14 at 01:53

1 Answers1

1

First, don't restrict your input to just string streams. Use the generic std::istream instead unless you have a solid reason to do otherwise. Your class will be more robust and able to source input from multiple source stream types, not just std::istringstream (such as a file stream or the input console).

Second I'm nearly certain this is what you're trying to do:

#include <iostream>

// forward declare class
template<class T>
class Finder;

// forward declare ostream inserter
template<class T>
std::ostream& operator <<(std::ostream&, const Finder<T>&);

// full class decl
template<class T>
class Finder
{
    // friend only the inserter that matches this type, as opposed to
    //  all inserters matching all T for Finder
    friend std::ostream& operator<< <>(std::ostream&, const Finder<T>&)
    {
        // TODO: implement inserter code here
    }

public:
    Finder()
    {
        // TODO: default initialization here
    };

    Finder(const T& value)
    {
        // TODO: initialize directly from T value here.
    }

    Finder(std::istream& input)
    {
        // TODO: initialize from input stream here.
    }

    ~Finder()
    {
        // TODO: either implement this or remove it outright. so far
        //  there is no evidence it is even needed.
    }

    T check(std::istream& input)
    {
        // TODO: implement check code here. currently just returning a
        //  value-initialized T. you will change it as-needed

        return T();
    };
};

A sample usage would be:

int main()
{
    Finder<int> f;

    std::istringstream iss("1 2 3");
    f.check(iss);
}

Notice there is one T, the one that comes from the class template itself. If there is a need for auxiliary types for member functions (or even the constructor) that is doable as well using template member function with a different type name, such as:

template<class T>
class Simple
{
public:
    // a template member constructor
    template<typename U> 
    Simple(const U& val)
    {
    }

    // a regular template member
    template<typename U>
    void func(U value)
    {
    }
};

and invoked like this:

Simple<int> simple(3.1415926); // U will be type double
simple.func("test");           // U will be type const (&char)[5]

Notice with the member function templates, like all function templates, the types are deduced from the parameters passed, not specified (though they could be to force a specific type, we don't here).

Anyway, hope it helps.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • Thank you! This isn't really what I was trying to do, but it did indirectly clear up the issue I was having. – Hydra- May 03 '14 at 02:28