1

我目前正在清理一个充满功能模板的API,并且强烈要求编写下面的代码。需要默认参数值的模板函数的首选设计是什么?

template <typename T, typename U, typename V> 
void doWork(const T& arg1, const U& arg2, V* optionalArg = 0); 

当我调用这个模板时,我想这样做如下。

std::string text("hello"); 
doWork(100, 20.0, &text); 
doWork('a', text);   // oops! 
doWork<char, std::string, void>('a', text); // to verbose! 

不幸的是,由于编译器无法推断出可选参数的类型,所以第二次调用不能编译。这是不幸的,因为我真的不在乎参数类型是什么,而是它的值是NULL。另外,我想避免第三次调用的路由,因为它妨碍了可读性。

这使我试图使模板参数V有一个默认类型,这也不起作用,因为您不能将默认类型应用于函数模板参数(至少使用VC++ 9.0)。

template <typename T, typename U, typename V = void> // oops! 
void doWork(const T& arg1, const U& arg2, V* optionalArg = 0); 

我唯一的选择是引入近朱者赤模板实参VdoWork过载。

template <typename T, typename U> 
void doWork(const T& arg1, const U& arg2) 
{ 
    doWork(arg1, arg2, 0); 
} 

template <typename T, typename U, typename V> 
void doWork(const T& arg1, const U& arg2, V* optionalArg); 

这是解决此问题的最佳方法吗?我看到的唯一缺点是,如果函数模板包含许多具有合适默认值的参数,我可能会引入许多简单的转发函数。

回答

5

我认为你的转发功能是一个完美的解决方案,虽然在你的解决方案中,你不需要明确指定模板参数吗? (0是一个整数常量,可以转换为任何V*类型。)还有doWorddoWork

作为一般规则,尽量避免可选参数,他们没有很强的回报。

可能更容易迫使你的客户端功能,只是增加一个, (void*)0如果appriopriate不是增加多少额外的机制,同时支持两个参数和模板的三个参数的版本。不过,这取决于预期的用途。

+0

是的,你是对的。应在转发功能中指定'0'的类型。 (FR) – 2009-10-12 17:38:58

0

一种可能性是重新排序模板参数,所以可选的一个首先来。

template <typename V, typename T, typename U> 
void doWork(const T& arg1, const U& arg2, V* optionalArg = 0); 

doWork<void>('a', text); 

转发看起来也不错。

但它似乎默认参数和模板不匹配,但。

2

从客户端代码的角度来看,如果它没有第三个参数,为什么需要发明一个?

所以,如果你的目标的实用性和可读性,我同意你的包装方法:它非常有意义,并且写的包装器,负责必要的第三个参数的一个体面的价值。

最重要的是,如果需要,它可以对不同的专业化使用不同的默认值。

+1

ISTR Francis Glassborow曾经说过,尽管超载和(内联)转发,首先发明了默认函数参数的原因是为了防止构造函数无法转发给每个构造函数的问题导致的代码重复其他。所以,除了构造函数之外,它是不必要的。 (请注意,在C++ 1x中,构造函数将能够相互转发。) – sbi 2009-10-11 20:22:45