2013-03-01 82 views
1

我有一个功能强制功能模板/函数重载为特定类型

foo(int, int, int, int/long long/_int64/double/long double/char *, int ONLY IF previous char * - otherwise unneeded)

问题是,字符*实现要比值类型,由于进行字符串拷贝不同。是的,这是一个旧代码的接口,所以我不能使用std :: string:/

目前,我已经把它作为模板,并且有一个函数重载char *,并带有额外的参数。但是,其他类型的所有操作在char *上也是有效的,所以如果调用者忘记了最后一个参数,则该函数默默地匹配模板,而不是产生错误的逻辑。

有没有什么办法可以强制使用函数模板中的重载/使用默认参数/这将允许特定类型的不同签名(额外参数),而不会默认匹配较小的签名?

更多: 尚未获得C++ 11的许可,但我很乐意看到使用它来帮助推动采用的建议。 没有提升,但与上面相同

我也曾尝试

return_type foo(int,int,int,typename std::enable_if<!std::is_pointer<T>::value, T>::type & value2update)

没有任何的运气。然后它声称带双&参数的呼叫无法匹配。

+0

你是什么意思,“否则不需要”?这应该通过重载轻松实现。 – Xeo 2013-03-01 23:42:01

+0

我假设额外的'int'是一个长度?你可以采取[StringPiece](http://code.google.com/p/re2/source/browse/re2/stringpiece.h)来避免完全需要特殊外壳? – 2013-03-01 23:43:07

+0

@Xeo,是的,我只是想避免每种类型的代码重复,所以想要templatize其他类型,这些都共享完全相同的代码。 @ Scott Lamb,是的,肯定这是一个有效的 - 也许是最好的选择。然而,这种集成将发生在代码库的大约3000个地方,所以不得不在调用代码中添加StringPiece创建逻辑,这是我想避免的。我只是希望有一些事情我做错了强制专业化 - 必须更彻底地调查Thomas的答案 – 2013-03-04 15:39:56

回答

2

你可以让你的链接帮助。声明,但没有定义,你的函数模板,char*超载头:

template<typename T> 
foo(int, int, int, T); 
foo(int, int, int, char*, int); 

在实现文件(的.cpp/.cc的),同时实现:

template<typename T> 
foo(int, int, int, T) { ... } 

foo(int, int, int, char*, int) { ... } 

,并明确实例版本对于类型要接受:

template<> 
foo(int, int, int, int); 
template<> 
foo(int, int, int, long long); 
// etc. 

如果我理解正确,ScottLam b在评论中暗示了这样的事情。头文件:

foo(int, int, int, int); 
foo(int, int, int, long long); 
... 
foo(int, int, int, char*, int); 

执行文件(.cpp /。立方厘米):

namespace { 
    template<typename T> 
    foo_tmpl(int, int, int, T) { ... } 
} 

foo(int, int, int, int) { foo_tmpl(...); } 
foo(int, int, int, long long) { foo_tmpl(...); } 
.... 
foo(int, int, int, char*, int) { ... } 

这是从使用报头的人的观点考虑,优选(它们可以立即看到哪些重载是可用的),但需要对实施侧略微更多的工作。

+1

恕我直言,如果列出每个支持的过载,恕我直言,标题将更直接/可读。如果定义不平凡,您可以委托给实现文件中的匿名名称空间中的模板函数以减少重复。 – 2013-03-02 02:12:50

+0

从外观来看,这是最好的答案。要明确,是头文件还是cpp文件中的显式实例? @ScottLamb你会不会解释你的评论?你是说如我刚刚提到的那样,实例化应该在头文件中列出,然后在cpp文件中定义它?顺便说一句,如果这改变了事情,这个整个类在一个命名空间范围 – 2013-03-04 15:56:54

+1

更新我认为他的意思。 – Thomas 2013-03-04 17:18:07

1

使用一个辅助类string_ref捆绑的两个参数为您提供:

class string_ref { 
    const char *str; 
    std::size_t len; 
public: 
    string_ref(std::string const& s) 
    : str(s.c_str()), len(s.size()) {} 

    string_ref(const char *c, std::size_t len) 
    : str(c), len(len) {} 

    const char * c_str() const { return str; } 
    std::size_t size() const { return len; } 
}; 

然后

foo(int, int, int, int/long long/_int64/double/long double/const char*, [int]) 

只需添加

foo(int, int, int, string_ref) 
{ 
    foo(int, int, int, c_str(), size()); 
} 

一个string_ref可以创建从const char*int没有开销,两者都可以轻松提取以便进一步传递给C函数。

(命名string_refnot random。)

+1

这不安全!只要字符串对象仍然存在并且未被修改,'std :: string :: c_str()'只是有效的。 – Thomas 2013-03-01 23:47:20

+1

如果小心使用,我不会看到问题。 'foo(...,string_ref(std :: string(“ok”)))'例如应该没问题。 – ipc 2013-03-01 23:49:24

+0

我喜欢这个答案,因为它是它应该完成的方式,我想 - 非常接近使用std :: string。另外,我赞赏没有任何开销的评论 - 在这种情况下这是非常关键的问题,而在其他情况下,在分析之后,更加优雅的面向对象的解决方案已经以原始速度被丢弃。它真的是“不”吗?我无法看到如何为此string_ref对象生成实际分配汇编程序指令。 – 2013-03-04 16:51:18