2

I have to admit that I steer clear of templates as much as possible. I want to change that. They shouldn't be so scary.

If I have functions declared like:

std::vector<SQLFieldObject> executeSelectQueryReturnSingleInt(std::string _sql);
std::vector<SQLPlantObject> executeSelectQueryReturnSingleInt(std::string _sql);
std::vector<SQLOrderObject> executeSelectQueryReturnSingleInt(std::string _sql);   

Where in executeSelectQueryReturnSingleInt(std::string _sql) The code is exactly the same for each function. I create a local version of the std::vector and return it.

I'd like to just have one generic executeSelectQueryReturnSingleInt(std::string _sql) function.

Templates might solve this, correct? Looking at example templates

template <class SomeType>
SomeType sum (SomeType a, SomeType b)
{
     return a+b;
}

What is confusing is that the parameters going in are the same, except the return vector is different.

Can anyone help me understand how to start applying templates to code reuse?

Jasmine
  • 15,375
  • 10
  • 30
  • 48

2 Answers2

4

You can do that:

template<typename SQLObject>
std::vector<SQLObject> executeSelectQueryReturnSingleInt(std::string _sql) {
    ...
}

then you call it as, for example,

executeSelectQueryReturnSingleInt<SQLPlantObject>("rose");

Note that you have to explicitly specify the template arguments because they can't be deduced from the function arguments, but otherwise this works like you'd expect.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • So would I create a `SQLObject` class and change my `SQLPlantObject` to subclass `SQLObject`? I otherwise dont see where SQLObjet would come from – Jasmine Apr 18 '14 at 18:45
  • 1
    Nope, `SQLObject` is just a placeholder name (like an argument name). Actually, the norm is to use `typename T`, but I chose a different name here so that it makes the intended usage more clear. – nneonneo Apr 18 '14 at 18:46
  • @nneonneo Did you mean to address the questions OP? – πάντα ῥεῖ Apr 18 '14 at 18:55
  • @nneoneo Using name `T` might be a norm, but using `typename` sure is not, especially considering there are cases where [`class` is required instead of `typename`](http://stackoverflow.com/a/2024173/3460805). – Chnossos Apr 18 '14 at 19:04
  • 3
    @Chnossos You are very much mistaken: `typename` is, if anything, used more often in my experience than `class` specifically to distinguish between the cases which require `class` and those that allow `class` or `typename` to be used interchangeably. – Casey Apr 18 '14 at 19:07
  • @nneonneo ok, that makes sense, I could use anything that means something to me/the function. – Jasmine Apr 18 '14 at 19:16
  • How does defining this in a header change? – Jasmine Apr 18 '14 at 21:24
  • @Casey This is not the behavior I observe around me, but I like the idea. I was taught that I'd better always use `class` to avoid having problems when it is required. – Chnossos Apr 18 '14 at 21:28
2

In this particular case, the template parameter would be the return type. You then have to use it explicitly when calling the function because it cannot be deduced from the function parameters:

template <typename ReturnType>
ReturnType executeSelectQueryReturnSingleInt(std::string sql)
{
     return ReturnType(args....);
}

Then

auto x = executeSelectQueryReturnSingleInt<std::vector<SQLFieldObject>>(sqlstr);

If you only want to return an std::vector of a particular type, then

template <typename SQLObjType>
std::vector<SQLObjType> executeSelectQueryReturnSingleInt(std::string sql)
{
     return std::vector<SQLObjType>(args....);
}

and

auto x = executeSelectQueryReturnSingleInt<SQLFieldObject>(sqlstr);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480