0

I have an error, and don't know what is cause, the error message which appeared undefined reference to int sqlite::bindParam<char const*>(char const*, char const*)

I have the following class

Class declaration: sqlite.h

class sqlite{

private:
sqlite3 *db_Connection;
sqlite3_stmt *sqlPrepare;

public:
    sqlite();
    int open(const char *db_fileName);
    int close();
    int query(const char *sql);
    template <class T>
    int bindParam(const char *parm_name, T parm_value);
    ~sqlite();
};

The method which is the cause of the problem: sqlite.cpp

template <class T>
int sqlite::bindParam(const char *parm_name, T parm_value){
    const std::type_info &parameter_name = typeid(parm_name);
    if(parameter_name == typeid(const char*) || parameter_name == typeid(char*)){
        return sqlite3_bind_text(sqlPrepare, sqlite3_bind_parameter_index(sqlPrepare, parm_name) ,parm_value, 0, 0);
    }else if(parameter_name == typeid(int)) {
        return sqlite3_bind_int(sqlPrepare, sqlite3_bind_parameter_index(sqlPrepare, parm_name), parm_value);
    }else if(parameter_name == typeid(double)){
        return sqlite3_bind_double(sqlPrepare, sqlite3_bind_parameter_index(sqlPrepare, parm_name), parm_value);
    }
}

When usage:

int main(){
    sqlite *sql = new sqlite();

    if(sql->open("database.db") == SQLITE_OK){
        cout << "Connected.";
        sql->query("SELECT * FROM categories WHERE name=:name");
        sql->bindParam<const char*>(":name", "Fruity");
    }

    delete sql;
    return 0;
}

I want to know what's wrong in my class specifically bindParam() method ?

Lion King
  • 32,851
  • 25
  • 81
  • 143
  • is the definition in a header file along with the class declaration ? all my senses tell me you've put `bindParam`'s definition in an implementation file – Piotr Skotnicki Dec 22 '14 at 18:50
  • 2
    The *vast* majority (not all, but nearly so) of undefined-reference linker errors regarding templates are because of incorrect location of the template implementation(s). [**Read this for more info**](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). – WhozCraig Dec 22 '14 at 18:56
  • @PiotrS.: the class declaration in independent file (`sqlite.h`), also the class definition in independent file (`sqlite.cpp`). and the two files along with. – Lion King Dec 22 '14 at 18:56
  • 2
    @LionKing so refer to [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Piotr Skotnicki Dec 22 '14 at 18:57
  • @LionKing why won't you just add overloads for `double`, `int` and `const char*` (`std::string`) instead of using templates with(!) RTTI ? – Piotr Skotnicki Dec 22 '14 at 19:02
  • @PiotrS.: I want to be simple and easy to use. – Lion King Dec 22 '14 at 19:07
  • @LionKing giving explicitly template type argument on each function call is easier than letting compiler do that by dispatching the call to proper overload? adding additional if-else branch whenever you want to support a new parameter type is more readable than additional overload? – Piotr Skotnicki Dec 22 '14 at 19:08
  • @PiotrS.: Can you give me an example for doing that ? – Lion King Dec 22 '14 at 19:11
  • @LionKing add member functions as follows: `int bindParam(const char *parm_name, const char* parm_value); int bindParam(const char *parm_name, double parm_value); int bindParam(const char *parm_name, int parm_value);` and define each separately, so that one calls `sqlite3_bind_text`, the second one `sqlite3_bind_double` and the last one calls `sqlite3_bind_int`. none is a function template, so they can go to implementation file just fine – Piotr Skotnicki Dec 22 '14 at 19:13
  • @PiotrS.: Thanks, but that is overload, and I don't want to use it. – Lion King Dec 22 '14 at 19:18
  • @LionKing any particular reason for that? – Piotr Skotnicki Dec 22 '14 at 19:20
  • @PiotrS.: Also unfortunately, I'm still don't understand what in the duplicate question link. – Lion King Dec 22 '14 at 19:31
  • @LionKing move the definition of `bindParam` to a header file, or add an explicit instantiation definition in an implemntation file – Piotr Skotnicki Dec 22 '14 at 19:33
  • @PiotrS.: `or add an explicit instantiation definition in an implemntation file`, how ? – Lion King Dec 22 '14 at 19:36
  • @LionKing put this at the end of the implementation file: `template int sqlite::bindParam(const char *parm_name, const char* parm_value); template int sqlite::bindParam(const char *parm_name, int parm_value); template int sqlite::bindParam(const char *parm_name, double parm_value);` – Piotr Skotnicki Dec 22 '14 at 19:40
  • @PiotrS.: Thanks, but there is no way except these ways only ? – Lion King Dec 22 '14 at 20:26
  • @LionKing no, no other options, out of which adding overloads in place of a function template is the best one – Piotr Skotnicki Dec 22 '14 at 20:32

1 Answers1

0

Since you're defining the function template in a source file that's not the same source file in which you're trying to use that function template, and since you didn't explicitly instantiate the function template in that source file, it cannot possibly be generated at the point where you need it.

In general it's better to define function templates inside the header files; yes, even though this is the opposite of what is advised for normal templates!

Community
  • 1
  • 1
Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • 3
    Actually, you *can* define templates in sources files but you need to explicitly instantiate the template in this case: implicit instantiation won't work. – Dietmar Kühl Dec 22 '14 at 19:04
  • @DietmarKühl: Yes but I wanted to keep it simple for this OP for now, and he or she can read the full FAQ for further details! :-) – Asteroids With Wings Dec 22 '14 at 19:07
  • 2
    @Asteroids The details should go into your answer. Otherwise it shows that you yourself don't really understand the OP's problem or the answer. –  Dec 22 '14 at 19:15