这是我的问题。我只是好奇在限制可以传递给泛型函数或类的类型方面的共识。我以为自己曾经读过,如果你正在进行通用编程,通常最好先把东西打开而不是试图关闭它们(不记得来源)。
我正在编写一个具有一些内部泛型函数的库,我觉得它们应该只允许库中的类型与它们一起使用,因为这就是我的意思。另一方面,我并不确定我努力锁定事情是值得的。
任何人都可能有一些关于这个主题的统计数据或权威评论?我也对合理的意见感兴趣。希望这并不能完全解决这个问题:\
此外,SO上是否有任何标签等同于“最佳实践”?我没有特别看到那个,但似乎能够为特定的SO主题提出所有最佳实践信息是有帮助的......也许不是,只是一个想法。
编辑:到目前为止,有一个答案提到我正在做的库类型很重要。它是一个数据库库,最终使用STL容器,可变参数(元组),Boost Fusion,这种性质的东西。我可以看到这是多么相关,但我也会对确定走哪条路的经验法则感兴趣。
答案 0 :(得分:14)
始终保持开放状态 - 但请务必
答案 1 :(得分:3)
它是STL最强大的卖点之一,它是如此开放,它的算法适用于我的数据结构以及它自己提供的算法,并且我的算法适用于其数据结构以及矿。
让你的算法对所有类型开放还是限制你的算法是否有意义在很大程度上取决于你正在编写的库,我们一无所知。
(最初我的意思是回答那个开放是通用编程的全部内容,但是现在我发现通用性总是存在限制,你必须在某个地方画线。它可能也仅限于你的类型,如果这是有道理的。)
答案 2 :(得分:3)
在我的数据库框架中,我决定放弃模板并使用单个基类。通用编程意味着可以使用任何或所有对象。特定类型类超过了一些通用操作。例如,可以比较字符串和数字的相等性; BLOB(二进制大对象)可能想要使用不同的方法(例如比较存储在不同记录中的MD5校验和)。
此外,字符串和数字类型之间存在继承分支。
通过使用继承层次结构,我可以使用Field
类或Field_Int
等专门类来引用任何字段。
答案 3 :(得分:2)
至少IMO,正确的做法大致是尝试的概念:而不是试图验证您是否正在接收指定类型(或指定类型集之一),请尽力指定要求类型,并验证您收到的类型是否具有正确的特征,并且可以满足模板的要求。
与概念非常相似,其中很大一部分动机就是在不满足这些要求时提供良好,有用的错误消息。最终,如果某人试图在不符合其要求的类型上实例化您的模板,编译器将产生错误消息。问题在于,除非您采取措施确保错误消息,否则错误消息将不会非常有用。
答案 4 :(得分:2)
问题
如果您的客户可以在公共标题中看到您的内部函数,并且这些内部通用函数的名称是“常见的”,那么您可能会让您的客户意外调用您的内部通用函数。
例如:
namespace Database
{
// internal API, not documented
template <class DatabaseItem>
void
store(DatabaseItem);
{
// ...
}
struct SomeDataBaseType {};
} // Database
namespace ClientCode
{
template <class T, class U>
struct base
{
};
// external API, documented
template <class T, class U>
void
store(base<T, U>)
{
// ...
}
template <class T, class U>
struct derived
: public base<T, U>
{
};
} // ClientCode
int main()
{
ClientCode::derived<int, Database::SomeDataBaseType> d;
store(d); // intended ClientCode::store
}
在此示例中,main
的作者甚至不知道Database :: store存在。他打算调用ClientCode :: store,并且变得懒惰,让ADL选择函数而不是指定ClientCode::store
。毕竟,他对store
的论证来自与store
相同的名称空间,所以它应该可以正常工作。
它不起作用。此示例调用Database::store
。根据{{1}}的内部结构,此调用可能会导致编译时错误,或者更糟糕的是,运行时错误。
如何修复
通常,您对功能命名越多,就越有可能发生这种情况。为内部函数(必须出现在标题中的函数)提供非通用名称。或者将它们放在像Database::store
这样的子命名空间中。在后一种情况下,您必须确保您的客户端不会将details
作为ADL的关联命名空间。这通常是通过不在details
中直接或间接创建客户端将使用的类型来实现的。
如果你想变得更偏执,可以用namespace details
开始锁定事情。
如果您认为您的内部职能可能对您的客户有用,那么他们就不再是内部职能了。
以上示例代码并非牵强附会。它发生在我身上。它发生在enable_if
中的功能中。我在此示例中将namespace std
称为过于通用。 store
和std::advance
是过于通用的代码的典型示例。这是值得警惕的事情。这是一个试图解决的概念问题。