如何写出完美的缩略函数模板?

How to write a perfect Abbreviated Function Template?

编写缩写函数模板的最佳做法是什么?

我明白,自 C++20 起,以下是有效代码:

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

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

decltype(auto) f(auto&& val) {return std::forward<decltype(val)>(val+=2);}
//something like this?: 
template<> decltype(auto) f<MyClass>(MyClass& val) {...}

Is it essential to use decltype(auto) as the return type of such functions?

取决于您返回的内容。使用缩写模板在这方面没有任何改变。

In particular, is the following code the right way to write abbreviated function templates?

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;

How should I specialize the above function?

//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;}

Is it essential to use decltype(auto) as the return type of such functions?

没有

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

An abbreviated function template is equivalent to a function template ([temp.fct]) whose template-parameter-list includes one invented type template-parameter for each generic parameter type placeholder of the function declaration, in order of appearance. For a placeholder-type-specifier of the form auto, the invented parameter is an unconstrained type-parameter.

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


How should I specialize the above function?

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

[...] [ Example:

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);

These declarations are functionally equivalent (but not equivalent) to the following declarations.

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);

Abbreviated function templates can be specialized like all function templates.

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

— end example ]

你可以专攻,比如说

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

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

DEMO.