带有默认参数的转发引用?

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,因此我更喜欢不包括编写多个重载的方式。

1个回答

3
首先,模板类型不能从默认参数中推导。因此,我们只能寻找其他方法来实现能够选择性地指定参数以匹配转发引用的想法。
这个解决方法自然而然地提出了:
template <typename Range, typename Encoding = encoder_t, typename Validation = validator_t>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator )
{
}

然而,这种方式失败了:转发引用通过将模板类型推断为引用类型来工作,但您已经指定了对象类型;而且rvalue引用现在无法绑定到您的虚拟对象的lvalues。正如您在帖子中所说,您可以通过使默认值成为临时对象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,那么也许这篇文章会有一些想法:如何在构造函数中使用通用引用时允许默认构造


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接