0

Background

I have a non-templated class which has a templated member function declared.

It looks similar to the following:

.hpp

class Foo
{
private:
    std::string libFilename;
    bool libLoaded;
    bool libFunctionsLoaded;
    HINSTANCE libHandle;
    std::map<std::string, long long int> libFunctions;
public:
    Foo(std::string libFilename);
    ~Foo(void);

    template<typename FunctionPointerType>
    FunctionPointerType getFunctionPtr(std::string functionName);

    void addUnitTestBlock(UnitTestBlock& newGroup);
};

template<typename FunctionPointerType>
FunctionPointerType Foo::getFunctionPtr(std::string functionName)
{
    return reinterpret_cast<FunctionPointerType>(this->libFunctions[functionName];);
}

The cpp has implementations to other functions. For the sake of making this readable, I am not including it. Basically, this implementation will load a bunch of dll functions from a library and put the names and the addresses (gathered from GetProcAddress()) into the map you see in class Foo.

This code has been verified and I can pull out an address and cast it to a function pointer and use the function just fine...

Problem

However, inside of the template function, the map is size = 0. For some reason the template function cannot see the proper class member when it comes to the map<>. It does see the proper values for libLoaded and libFunctionsLoaded. Additionally, the template function is not called until after the libFunctions map has been populated.

Here is how main is structured, just to give you an idea of the call pattern:

//DLL Function pointer prototypes
typedef int (*TestFunction)(int,char);

//Loads the whole DLL and populates the member variables including the map...
Foo libraryLoader= Foo("library.dll");


    TestFunction function = libraryLoader.getFunctionPtr<TestFunction>("testFunc");

    if(function(2, 'a') == 99)
    {
        std::cout << "Pass" << std::endl;
    }
    else
    {
        std::cout << "Fail" << std::endl;
    }

This will pass if I get rid of the template and just do the cast.

My goal was to remove the need for casting on the users part, and just have them pass the type of the Function Pointer in and cast it for them. Any ideas on why the template function cannot see a std::map but it can see a bool?

Dean Knight
  • 660
  • 6
  • 17
  • Where does the template function access the map? – dlf Nov 18 '14 at 21:38
  • Possible duplicate of [Why can templates only be implemented in the header file?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file)? – πάντα ῥεῖ Nov 18 '14 at 21:38
  • Also in this: `FunctionPointerType LibraryTester::getFunctionPtr(std::string functionName)`, do you mean `Foo` instead of `LibraryTester`? – dlf Nov 18 '14 at 21:40
  • @dlf yes. Sorry i was stripping it out for the question to be a bit more simple. I will also add where the template is accessing the map. I had added another local function that did the access hoping it could see the map properly. But that did not change a thing, which is what made me believe I was not utilizing something within the language correctly, leading me here. – Dean Knight Nov 19 '14 at 03:04
  • @πάνταῥεῖ I had a similar thought as the people in that question, however I thought this would behave differently since it is a template method in a non-templated class. I would think that the templated method would be instantiated inside of the classes address space at compile time, being able to see variables belonging to the class. This template method can see the booleans and the std::string as well as the HINSTANCE. All of these are verified the same inside the template method and outside of it. The only thing behaving differently is this map. – Dean Knight Nov 19 '14 at 03:12
  • I don't have VS2012 available right now, but I tried this in 2013 and it worked fine. What does the code that populates the map look like? Or; could it be that your full implementation of the template function declares a local variable named `libFunctions` that hides the class member? – dlf Nov 19 '14 at 03:28
  • See this for example: http://coliru.stacked-crooked.com/a/fa7dabedb7d08950 – dlf Nov 19 '14 at 03:35
  • @dlf I too only have VS2013 available. I just wrote a quick test to confirm that a map can be read.. the code that instantiates that map object is quite complicated and obviously something is not being passed correctly. And you know what, operator= could very well be a suspect. I dont get to interact with the main codebase until Thursday. I will run through it and figure out where I was passing. Either that, or VS2012 has a bug? I doubt it though. Im willing to bet i passed something incorrectly. Write up an answer and when i figure out what went wrong, I will accept. – Dean Knight Nov 19 '14 at 03:46
  • I misspoke before; it is actually the copy constructor that is being called, not operator= (at least under VS2012; in coliru, neither is called...). So a bug there could be responsible. – dlf Nov 19 '14 at 15:39
  • With a slight restructuring, I can prevent coliru from eliding the copy and demonstrate how a broken copy ctor could cause what you're seeing: http://coliru.stacked-crooked.com/a/93fbdf7920edd8bb – dlf Nov 19 '14 at 15:48
  • @dlf So, I found the problem. I loaded everything in the regular constructor, and overwrote the map after it got loaded. The default copy ctor actually worked fine since I was using simple types and no pointers. However, I did write a copy ctor because I should have from the start... Thanks for the help. You deserve rep and the copy ctor point is valid and should be recorded in an answer for future users. – Dean Knight Nov 20 '14 at 14:03
  • Glad to hear it. It sounds like you solved the problem yourself though, even if I provided some clues. I doubt future sufferers of broken copy constructors will find this question, so I'm not sure there'd be a lot of benefit to turning those comments into an answer, especially since it wasn't actually your problem. At the end of the day 25 rep more or less doesn't matter that much, so I'd say just write up your own answer and accept it. :) – dlf Nov 20 '14 at 16:11

1 Answers1

0

Check your default constructor, copy constructor, and any other custom constructors/move/operator functions you write/overload. Make sure these are doing what you think they are doing.

Templated functions work just fine in non-templated classes. Data being inaccurate or missing is most likely a copy issue.

Edit: As pmr mentions below... Obey the rule of five. That is definitely the main point.

Dean Knight
  • 660
  • 6
  • 17