peer_2_peer_2
peer_2_peer_2

Reputation: 135

C++ class template method for varied parameter types

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

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

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

Related Questions