【问题标题】:How to write a perfect Abbreviated Function Template?如何编写一个完美的缩写函数模板?
【发布时间】:2020-06-30 08:42:18
【问题描述】:

编写缩写函数模板的最佳实践是什么?

我了解,从 C++20 开始,以下是有效代码:

void f(auto&& val) {...}

是否必须使用 decltype(auto) 作为此类函数的返回类型? 特别是,下面的代码是编写缩写函数模板的正确方法吗?

decltype(auto) f(auto&& val) {return std::forward<decltype(val)>(val+=2);}
  • 我应该如何专门化上述功能?
//something like this?: 
template<> decltype(auto) f<MyClass>(MyClass& val) {...}

【问题讨论】:

  • void f(auto&amp;&amp; val) {...} 不是有效代码。
  • @Axalo - 这是由于 C++20 标签
  • @Axalo 是,从 C++20 开始。忽略...,即。
  • @StoryTeller-UnslanderMonica 我相信前两个问题是相同的(基本上我只是在第一个问题的第二个问题中给出了一个“默认”示例)。第三个问题我会去掉,单独问。
  • @StoryTeller-UnslanderMonica 我已经得到了几个答案,所以我将保持原样。下次我会试着问一个更中肯的问题。

标签: c++ templates auto c++20


【解决方案1】:

必须使用decltype(auto) 作为此类函数的返回类型吗?

取决于您返回的内容。在这方面,使用缩写模板不会改变任何事情。

特别是,下面的代码是编写缩写函数模板的正确方法吗?

decltype(auto) f(auto&& val) {return std::forward<decltype(val)>(val+=2);}

decltype(auto) 使用正确。但是val 应该在对其进行任何操作之前转发:

std::forward<decltype(val)>(val) += 2;

或者,你可以写:

decltype(val)(val) += 2;

我应该如何专门化上述功能?

//something like this?: 
template<> decltype(auto) f<MyClass>(MyClass& val) {...}

参数的类型为T &amp;&amp;,其中T 是隐式模板参数。所以它必须是f&lt;MyClass&gt;(MyClass&amp;&amp; val)f&lt;MyClass &amp;&gt;(MyClass&amp; val)。你也可以省略模板参数,让编译器推断它。

但请注意,这种特殊化仅适用于非常量、右值(或左值)MyClass 参数。如果您想专门化参数的所有值类别和 cv 限定符的组合,则需要重载它(因为您不能部分专门化函数):

template <typename T>
requires std::same_as<int, std::remove_cvref_t<T>>
decltype(auto) f(T&& val) {return 42;}

或者:

decltype(auto) f(auto&& val)
requires std::same_as<int, std::remove_cvref_t<decltype(val)>>
{return 42;}

【讨论】:

  • 感谢您的详细解释!我取消了对问题第二部分的删除,以使阅读本文的人更容易理解您的答案。
【解决方案2】:

必须使用decltype(auto) 作为此类函数的返回类型吗?

没有。

来自[dcl.fct]/18/sentence-2 [摘录,强调我的]:

一个缩写的函数模板等价于一个函数模板([temp.fct]),它的模板参数列表 包括一个发明的类型函数声明的每个通用参数类型占位符的模板参数,按出现顺序。对于auto 形式的占位符类型说明符 ,发明的参数是不受约束的类型参数.

因此,常规函数模板和缩写函数模板 w.r.t 之间没有本质区别。使用decltype(auto) 作为返回类型;它只是让您能够完美地转发返回类型(与常规函数模板一样)。


我应该如何专门化上述功能?

根据[dcl.fct]/18 [摘录,强调我的]:

[...] [示例:

template<typename T>     concept C1 = /* ... */;
template<typename T>     concept C2 = /* ... */;
template<typename... Ts> concept C3 = /* ... */;

void g1(const C1 auto*, C2 auto&);
void g2(C1 auto&...);
void g3(C3 auto...);
void g4(C3 auto);

这些声明在功能上等价于(但不等价于) 以下声明。

template<C1 T, C2 U> void g1(const T*, U&);
template<C1... Ts>   void g2(Ts&...);
template<C3... Ts>   void g3(Ts...);
template<C3 T>       void g4(T);

缩写函数模板可以像所有函数模板一样专门化。

template<> void g1<int>(const int*, const double&); // OK, specialization of g1<int, const double>

—结束示例]

你可以专攻,比如说

void f(auto&& val) { (void)val;}

作为

template<>
void f<int>(int&& val) { (void)val;}

DEMO.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-23
    • 2023-01-05
    相关资源
    最近更新 更多