【问题标题】:C++ template function unused typenameC++ 模板函数未使用的类型名
【发布时间】:2020-08-09 14:36:20
【问题描述】:

我正在尝试了解 C++ 模板并复制语义。 我明白为什么我不能打电话给assign1(它要求提供右值引用,我提供了一个左值引用) 但是为什么我可以调用 assign2 来施加相同的约束呢?

template<typename... Args>
void assign1(Args&& ... arguments) { }

template<typename A, typename... Args>
void assign2(Args&& ... arguments) { }

template<typename A, typename B, typename... Args>
void assign3(Args&& ... arguments) { }

int main() {
    const int r = 2;
    assign1<int>(r);        // no matching function for call to...
    assign2<int>(r);        // ok!
    assign3<int>(r);        // no matching function for call to...
}

【问题讨论】:

  • 对于assign1,您显式指定了参数类型,实际参数无法转换为该类型。对于assign2,您明确指定A,但A 不用于任何用途。相反,Args 会自动从参数类型推导出来。

标签: c++ templates forwarding-reference


【解决方案1】:

给定assign1&lt;int&gt;(r);,你明确指定了模板参数,那么assign1的参数类型将是int&amp;&amp;,正如你所说,它是右值引用,不能与左值绑定。

给定assign2&lt;int&gt;(r);,您将第一个模板参数A 指定为int,参数包Args 将从函数参数r 推导出来。请注意,它不是右值引用,而是forwarding reference,它可以同时接受左值和右值。 (根据函数参数是左值还是右值,根据类型推导结果,函数参数类型为左值引用或右值引用。)

给定assign3&lt;int&gt;(r);,您只指定了第一个模板参数A,但无法从函数参数推导出第二个参数参数B,因此调用失败。


如果你想让函数模板只接受右值,你可以加static_assertlike

template<typename A, typename... Args>
void assign2(Args&& ...) { 
    static_assert(((!std::is_lvalue_reference_v<Args>) && ...), "must be rvalue");
}

LIVE

或申请SFINAE

template<typename A, typename... Args>
std::enable_if_t<((!std::is_lvalue_reference_v<Args>) && ...)> assign2(Args&& ...) {
}

LIVE

或者添加另一个采用左值引用的重载并将其标记为delete。 (这种方法只有在所有参数都是左值时才有效。)

template<typename A, typename... Args> 
void assign2(Args& ... arguments) = delete;

LIVE

【讨论】:

  • 我不明白这一点“注意它不是右值引用而是转发引用”。抱歉,我是 C++ 新手,我认为 &amp;&amp; 意味着该函数需要一个 r 值 ref
  • @FRR 当您按照代码中显示的语法声明它时,它成为转发引用;请参阅here 了解更多信息。
  • 谢谢!所以这是某种“特殊”情况。我觉得有点奇怪。如果我想强制我的模板函数只接受“r-value”引用怎么办?
  • @FRR 您可以添加static_assert 或SFINAE 来将类型约束为右值引用,或者添加一个采用左值引用的重载并将其标记为delete。例如template&lt;typename A, typename... Args&gt; void assign2(Args&amp; ... arguments) = delete;.
  • 谢谢! C++ 确实很奇怪,我从这个&amp;&amp; 得到的意思是在函数/类templates 中使用时略有不同。随着我对这种语言越来越熟悉,我会记住这一点。感谢您的帮助!
猜你喜欢
  • 2018-05-01
  • 1970-01-01
  • 2021-09-21
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
相关资源
最近更新 更多