【问题标题】:Class template instantiations and universal references类模板实例化和通用引用
【发布时间】:2017-04-11 00:40:43
【问题描述】:

在这样的代码中:

template<class...> struct pack{};

template<class, class = int>
struct call_t
{
    template<class... args_t>
    static int apply(args_t&&...)
    { return 0; }
};

template<class... args_t>
struct call_t<pack<args_t...>, // (1)
        std::decay_t<decltype(convert(declval<args_t>()...))> >
{
    template<class... params_t> // (2)
    static int apply(params_t&&... args)
    { return convert(std::forward<params_t>(args)...); }
};

template<class... args_t>
auto test(args_t&&... args) // (3)
{
    return call_t<pack<args_t...> >::
       apply(std::forward<args_t>(args)...);
}

此函数根据函数convert 是否存在并将一组参数发送到一个函数或另一个函数,并且可以使用传递的参数调用,保持完整(我猜)它们的确切传递类型,并且它的返回类型是int,与引用或 const 限定符无关。

我对那段代码有三个疑问。

  • (1) declval 返回类型仍然是通用引用吗?例如,declval&lt;T&gt;()T = int&amp;,其返回类型将是 int&amp;&amp;(真正的 r 值引用),还是 int &amp; &amp;&amp; 并在传递时遵循通用引用的通常规则再次推导出为 int&amp;到另一个电话?我认为它没有(正如@101010 所指出的那样),但我不知道在这种情况下如何进行完美的重载测试。

  • (2) 是否需要重新指定可变参数模板才能使用通用引用推导规则,或者由于(3)中已经推导了正确的类型,所以它们保持推导的类型不变?

或者我可以写吗

template<class... args_t>
struct call_t<pack<args_t...>, // (1)
        std::decay_t<decltype(convert(declval<args_t>()...))> >
{
    // (2)
    static int apply(args_t... args)
    { return convert(args...); }
};

?

call_t 模板类是一个实现细节,因此,它将仅在 test 内部实例化。

【问题讨论】:

  • 关于第一个问题:std::decval 的返回类型是 T&amp;&amp;,除非 T 是(可能是 cv-qualified)void,在这种情况下返回类型是 T
  • 所以我失去了(3)中传递参数的原始类型。问题是我不知道如何进行完美的“重载测试”(在未评估的上下文中),或者至少不涉及更多额外的辅助模板。
  • 不,如果T = int&amp; 例如,T&amp;&amp; 确实是 int&amp; 通过引用折叠规则
  • 由于您的代码正在运行,我认为这是CodeReview的问题
  • @J.H.Bonarius 我不想表现得像个“巨魔”,在不同的地方发布相同的问题。我的问题有两种性质,如果它对任何convert 重载都能可靠地工作(我认为这个问题更接近于 StackOverflow,但我没有失败的用例),以及如果模板 (2) 是多余的(也许更多适合 CodeReview,因为我认为它不会影响预期目的的“语义”)。

标签: c++ templates c++14 forwarding-reference


【解决方案1】:

这两种情况等价。这个例子:

template<class... args_t>
struct call_t<pack<args_t...>, // (1)
        std::decay_t<decltype(convert(declval<args_t>()...))> >
{
    // (2)
    static int apply(args_t... args)
    { return convert(args...); }
};

不转发任何内容。参数包args... 是左值,因为它们有名称。这与这段代码非常不同:

template<class... params_t> // (2)
static int apply(params_t&&... args)
{ return convert(std::forward<params_t>(args)...); }

其中args... 转发。产生的行为是新示例可能比旧示例慢(执行复制而不是移动),或者可能只是令人惊讶地无法编译。考虑convert(std::unique_ptr&lt;int&gt; ) 可以用args_t = {std::unique_ptr&lt;int&gt;} 调用,但内部的apply() 会失败,因为您会尝试复制unique_ptr

你需要这样做:

static int apply(args_t... args)
{ return convert(std::forward<args_t>(args)...); }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-23
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多