5

我在试图弄清楚如何为转发引用(以前被 Scott Meyers称为通用引用)指定默认参数时遇到了麻烦。

这是尝试做我想做的事情的代码示例:

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" );

}

也可在 Coliru 上获得

通过错误处理,您发现可以通过默认模板参数使其工作,然后在其后默认构造参数:

// 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() ) {

}

也在 Coliru 上

这是处理这个问题的“正确”方式吗?我应该使用什么语法?是否有多种方法可以达到“默认转发引用”的预期效果?我应该以哪种方式写这个?还要记住,稍后我将在代码上撒上大量的 SFINAE,所以我更喜欢不包括编写多个重载的东西。

4

1 回答 1

3

首先,模板类型不能从默认参数中推导出来。所以我们只能寻找其他方法来实现能够选择性地指定一个参数来匹配转发引用的想法。

这种解决方法本身就表明:

template <typename Range, typename Encoding = encoder_t, typename Validation = validator_t>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator )
{
}

但是这失败了:转发引用通过将模板类型推断为引用类型来工作,但是您已经指定了对象类型;并且右值引用现在无法绑定到虚拟对象的左值。

正如您在帖子中所说,您可以通过将默认值设为临时对象encoder_t{}而不是虚拟对象来解决此问题。这个问题证实了在这种情况下引用确实仍然是转发引用。

另一种解决方法是使用单独的构造函数而不是默认参数:

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

于 2014-11-27T02:24:29.497 回答