简体   繁体   English

当需要特定于类型参数的代码时是否应该使用模板?

[英]Should templates be used when type-parameter-specific code is needed?

Imagine we have a class responsible for setting values for SQL prepared statements like these:想象一下,我们有一个类负责为 SQL 准备好的语句设置值,如下所示:

void MySqlPreparedStatement::SetString(uint32_t paramIndex, const std::string& value);
void MySqlPreparedStatement::SetBinary(uint32_t paramIndex, const void* value, size_t length);
void MySqlPreparedStatement::SetUInt64(uint32_t paramIndex, const uint64_t value);
void MySqlPreparedStatement::SetInt64(uint32_t paramIndex, const int64_t value);
// ...

All these "set" methods have code that is common among them but still have some code that depends on the type of the value the user is setting in (eg m_parameters[paramIndex].buffer_type = MYSQL_TYPE_LONGLONG; for 64 bit integers and m_parameters[paramIndex].buffer_type = MYSQL_TYPE_LONG; for 32 bits integers).所有这些“设置”方法都有一些通用的代码,但仍然有一些代码取决于用户设置的值的类型(例如m_parameters[paramIndex].buffer_type = MYSQL_TYPE_LONGLONG;对于 64 位整数和m_parameters[paramIndex].buffer_type = MYSQL_TYPE_LONG;对于 32 位整数)。

In this case, which one is a better practice?在这种情况下,哪个是更好的做法? Encapsulate all of these "set" methods in only one template method (which will make me create some switch/case on each accepted type-argument to get the correct value for buffer_type ) or just declare different methods for each accepted type of value like the declarations I showed above?将所有这些“设置”方法封装在一个模板方法中(这将使我在每个接受的类型参数上创建一些 switch/case 以获得正确的buffer_type值)或者只是为每个接受的值类型声明不同的方法,例如我上面显示的声明?

What is most suitable depends heavily on the code contained in the functions.什么最合适在很大程度上取决于函数中包含的代码。

If you can clearly separate specific code and common identical code, then encapsulating this identical code in a separate function and call that one from smaller functions containing the specific parts might be more suitable (shortening signature a bit):如果您可以清楚地将特定代码和常见的相同代码分开,那么将这个相同的代码封装在一个单独的函数中并从包含特定部分的较小函数中调用它可能更合适(稍微缩短签名):

void setUInt64(uint64_t value)
{
    // some code specific to uint64_t, maybe converting to binary or textual representation
    setParameter(/*...*/, sizeof(value), MYSQL_TYPE_LONGLONG);
}

(According to your comments, that seems to be the case in your concrete example.) (根据您的评论,在您的具体示例中似乎就是这种情况。)

Matter changes, though, if you have common code and specific code intermixed (extending the point of view):但是,如果您将公共代码和特定代码混合在一起(扩展观点),则情况会发生变化:

void setInt32(int32_t value)
{
    firstCommonFunction(/*...*/);
    // some specific code
    secondCommonFunction(/*...*/);
}

Would you really want to implement that pattern for every function?你真的想为每个函数实现那个模式吗? While above might be a corner case, you're better off with a template if the function gets even more complex:虽然上面可能是一个极端情况,但如果函数变得更加复杂,你最好使用模板:

template <typename T>
void setParameter(T const& value)
{
    firstCommonFunction(/*...*/);
    firstSpecificFunction<T>(/*...*/);
    secondCommonFunction(/*...*/);
    secondSpecificFunction<T>(/*...*/);
    thirdCommonFunction(/*...*/);
    thirdSpecificFunction<T>(/*...*/);
    fourthCommonFunction(/*...*/);
}

Now a template assures that all your functions behave alike, calling common and specific functions whenever appropriate.现在,模板可确保您的所有函数都具有相同的行为,并在适当的时候调用通用和特定函数。

That's fine if your functions all look like that by design anyway.如果您的功能在设计上看起来都这样,那很好。 However, artificially enforcing such a design by all means solely for the sake of being able to have a template usually is not that a good idea...但是,仅仅为了能够拥有模板而人为地强制执行这样的设计通常不是一个好主意......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM