我无法弄清楚如何为转发参考指定默认参数(之前由Scott Meyers指定为Universal References)。
以下是尝试执行我想要执行的操作的代码示例:
struct encoder_t {
} const encoder = {};
struct validator_t {
} const validator = {};
struct test {
template <typename Range, typename Encoding, typename Validation>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator ) {
}
};
int main() {
test( "woof" );
}
搞清楚错误,你会发现你可以通过默认模板参数使其工作,然后默认构造参数:
// Works! But the syntax is strange... potential ramifications/deduction mishaps?
// Is this the "proper" way to default these arguments?
template <typename Range, typename Encoding = encoder_t, typename Validation = validator_t>
test ( Range&& range, Encoding&& encoding = Encoding(), Validation&& validation = Validation() ) {
}
这是处理此问题的“正确”方法吗?我应该使用什么语法?有多种方法可以获得“默认转发参考”的预期效果吗?我应该用哪种方式写这个?还要记住,稍后我将在代码上撒上大量的SFINAE,所以我更喜欢不包括写多个重载的东西。
答案 0 :(得分:3)
首先,template types cannot be deduced from default arguments。因此,我们只能寻找其他方法来实现能够选择性地指定参数以匹配转发引用的想法。
这种解决方法表明了自己:
template <typename Range, typename Encoding = encoder_t, typename Validation = validator_t>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator )
{
}
然而这失败了:转发引用通过将模板类型推断为引用类型来工作,但是您已经指定了对象类型;并且rvalue引用现在不能绑定到虚拟对象的左值。
正如您在帖子中所说,您可以通过将默认值设置为临时对象encoder_t{}
而不是虚拟对象来解决此问题。 This question确认在这种情况下引用仍然是转发引用。
另一种解决方法是使用单独的构造函数而不是默认参数:
template <typename Range>
test ( Range&& range )
{
}
template <typename Range, typename Encoding>
test ( Range&& range, Encoding&& encoding )
{
}
template <typename Range, typename Encoding, typename Validation>
test ( Range&& range, Encoding&& encoding, Validation&& validation )
{
}
根据您在构造函数体中的确切操作,可以使用构造函数委派实现此目的。
既然你提到了加入SFINAE的意图,也许这篇文章会有一些想法:How to allow default construction when using universal reference in constructor