Reputation: 135
I am wrapping some sqlite stuff and I was wondering if, maybe using templates, I could avoid having to wrap each type with a new method. However, I am absolutely lost, fumbling around with templates. I cannot find a great tutorial.
This is what my Statement class looks like right now
class Statement {
public:
Statement();
~Statement();
void BindInt(int index, int value);
void BindInt(std::string name, int value);
void BindInt64(int index, int value);
void BindInt64(std::string name, int value);
void BindText(int index, std::string value);
void BindText(std::string name, std::string value);
};
Statement::Statement(){}
Statement::~Statement(){}
void Statement::BindInt(int index, int value){}
void Statement::BindInt(std::string name, int value){}
void Statement::BindInt64(int index, int value){}
void Statement::BindInt64(std::string name, int value){}
void Statement::BindText(int index, std::string value){}
void Statement::BindText(std::string name, std::string value){}
I feel like I could write something else that is generic, like
class Statement {
public:
Statement();
~Statement();
template<class T, class V>
void Bind(T param, V value);
};
Statement::Statement(){}
Statement::~Statement(){}
template<class T, class V>
void Statement::Bind(T index, T value){}
But I would need to know what type of value was passed in value
so I can call the correct underlying function, eg sqlite_bind_int
or sqlite_bind_text
, etc. Is this possible?
Upvotes: 3
Views: 58
Reputation: 122298
But I would need to know what type of value was passed in value ....
You do know the type. It is V
.
... so I can call the correct underlying function, eg sqlite_bind_int or sqlite_bind_text, etc. Is this possible?
If you need to call a different method for each type passed as value
you wont gain much from using templates. You would end up writing a specialization for each possible type to call the corresponding sqlite_bind_XY
function. You can get the same much easier with overloads:
class Statement {
public:
Statement();
~Statement();
void Bind(int index, int value); // aka BindInt
void Bind(std::string name, int value);
void Bind(int index, int64_t value); // aka BindInt64
void Bind(std::string name, int64_t value);
void Bind(int index, std::string value); // aka BindText
void Bind(std::string name, std::string value);
};
Note that I had to change int
to int64_t
to make them different. You would have the same issue with templates. Sometimes there is no obvious way to make the parameters different, then you can use tags:
class Statement {
public:
struct text_tag{};
struct int_tag{};
struct int64_tag{};
Statement();
~Statement();
void Bind(int_tag,int index, int value); // aka BindInt
void Bind(int_tag,std::string name, int value);
void Bind(int64_tag,int index, int value); // aka BindInt64
void Bind(int64_tag,std::string name, int value);
void Bind(text_tag,int index, std::string value); // aka BindText
void Bind(text_tag,std::string name, std::string value);
};
As a super simplified rule of thumb to be taken with a grain of salt: when you want to do something different for each type use overloads when you want to do the same for each type use templates.
PS: as pointed out by @Mils Budnek "You get a slightly nicer interface to your class IMO, but templates certainly don't lead to simpler code in this case." I do agree, but concentrated on advocating overloads ;).
Upvotes: 3