0

I am trying to call the following function template:

    template<typename T>
    bool select(const std::string& ddbbName,
                const std::string& sql,
                std::vector<std::shared_ptr<T>>& vResultSet,
                SqlErrorInfo& errorInfo);

which is defined in a class whose name is SQLite3Manager. In the following code this "select" method does nothing (a part from returning "true"). I have tried to simplify the problem description, because the problem seems to be related to the way I am calling/using/defining that method.

So the main.cpp code is:

main.cpp

#include <iostream>
#include "ES.h"
#include "SQLiteMgr.h"

int main(int argc, const char * argv[])
{
  // To get an instance of the singleton
  Cucut::SQLite3Manager& _sqliteMgr = Cucut::SQLite3Manager::getInstance();
  std::string ddbbName("Cucut.db");
  std::string sql("SELECT * FROM ES");
  std::vector<std::shared_ptr<Cucut::ES>> vspEs;
  Cucut::SqlErrorInfo sqlErrorInfo;
  // Call the template method for <Cucut::ES> using the instance of the singleton
  bool result = _sqliteMgr.select<Cucut::ES>(ddbbName, sql, vspEs, sqlErrorInfo);

  return result;
}

but I get the following link error in Xcode 5:

Undefined symbols for architecture x86_64:
"bool Cucut::SQLite3Manager::select<Cucut::ES>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::shared_ptr<Cucut::ES>, std::__1::allocator<std::__1::shared_ptr<Cucut::ES> > >&, Cucut::SqlErrorInfo&)", referenced from:
  _main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The full code is:

ES.h file:

#ifndef __TestSharedPtr__ES__
#define __TestSharedPtr__ES__

#include <iostream>

namespace Cucut
{
    class ES
    {
    public:
        ES();

        const unsigned int& getId() const;
        void setId(const unsigned int& id);

    private:
        unsigned int _id;
    };
}

#endif /* defined(__TestSharedPtr__ES__) */

ES.cpp file:

#include "ES.h"

namespace Cucut
{
    ES::ES() :
    _id(0)
    {
    }

    const unsigned int& ES::getId() const
    {
        return _id;
    }

    void ES::setId(const unsigned int& id)
    {
        _id = id;
    }
}

SQLiteMgr.h file:

#ifndef __TestSharedPtr__SQLiteMgr__
#define __TestSharedPtr__SQLiteMgr__

#include <iostream>
#include <vector>
#include <memory>

namespace Cucut
{
    struct SqlErrorInfo
    {
        int rc;
        std::string description;
    };

    class SQLite3Manager
    {
    private:

        SQLite3Manager();
        SQLite3Manager(const SQLite3Manager& rs);
        SQLite3Manager(SQLite3Manager&& rs);
        SQLite3Manager& operator = (const SQLite3Manager& rs);
        SQLite3Manager& operator = (SQLite3Manager&& rs);

    public:

        static SQLite3Manager& getInstance();
        template<typename T>
        bool select(const std::string& ddbbName,
                    const std::string& sql,
                    std::vector<std::shared_ptr<T>>& vResultSet,
                    SqlErrorInfo& errorInfo);
    };
}

#endif /* defined(__TestSharedPtr__SQLiteMgr__) */

And finally the SQLiteMgr.cpp file:

#include <memory>
#include <vector>
#include "SQLiteMgr.h"

namespace Cucut
{
    SQLite3Manager::SQLite3Manager()
    {
    }

    SQLite3Manager& SQLite3Manager::getInstance()
    {
        static SQLite3Manager instance;

        return instance;
    }

    template<typename T>
    bool SQLite3Manager::select(const std::string& ddbbName, 
                                const std::string& sql,
                                std::vector<std::shared_ptr<T>>& vResultSet,
                                SqlErrorInfo& errorInfo)
    {
        return true;
    }
}

Do not be distract with the name "SqliteMgr" because in the aforementioned example I have removed any kind of reference to sqlite3 in order to simplify the problem; so, it seems that I am not calling or defining the method "select" in the correct way because I get the aforementioned link error.

Any help will be appreciated. Thanks in advance.

Genar
  • 725
  • 1
  • 10
  • 27

1 Answers1

2

Function template definitions must always be in the header file so that code can be generated at the point of instantiation (here in main). If you don't do this, the compiler will expect you to manually instantiate the template, which is why there is a linker error. Move the body of the select function to SQLiteMgr.h and it will work.

  • You are totally right! The first time I programmed that class I did not use any template, but after modifying it I forgot to move the body of that template method to the header. Thanks a lot! – Genar Mar 11 '14 at 12:08