编写缩写函数模板的最佳实践是什么?
我了解,自 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) {...}
是否必须使用
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 &&
,其中T
是隐式模板参数。所以它必须是f<MyClass>(MyClass&& val)
或f<MyClass &>(MyClass& val)
.您也可以省略模板参数,让编译器推断它。
但请注意,这种特殊化仅适用于非常量、右值(或左值(MyClass
参数。如果你想专门研究参数的所有值类别和 cv-qualifers 的组合,你需要重载它(因为你不能部分专化函数(:
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;}
必须使用
decltype(auto)
作为此类函数的返回类型?
不。
摘自[dcl.fct]/18/句子-2 [摘录,强调我的]:
缩写函数模板等效于函数模板 ([temp.fct](,其模板参数列表包括一个发明的类型模板参数,用于函数声明的每个泛型参数类型占位符(按出现顺序(。对于形式
auto
的占位符类型说明符,发明的参数是一个不受约束的类型参数。
因此,常规函数模板和缩写函数模板之间没有本质区别,因为使用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;}
演示。