What are the best practices to write abbreviated function templates?
I understand, that since C++20, the following is valid code:
void f(auto&& 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);}
//something like this?:
template<> decltype(auto) f<MyClass>(MyClass& val) {...}
Is it essential to use
decltype(auto)
as the return type of such functions?
Depends on what you're returning. Using an abbreviated template doesn't change anything in this regard.
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)
is used correctly. But val
should be forwarded before doing anything with it:
std::forward<decltype(val)>(val) += 2;
Alternatively, you could write:
decltype(val)(val) += 2;
How should I specialize the above function?
//something like this?: template<> decltype(auto) f<MyClass>(MyClass& val) {...}
The parameter has type T &&
, where T
is the implicit template parameter. So it must be either f<MyClass>(MyClass&& val)
or f<MyClass &>(MyClass& val)
. You could also omit the template parameter, and let the compiler infer it.
But note that this specialization applies only to a non-const, rvalue (or lvalue) MyClass
argument. If you want to specialize for all value categories and combinations of cv-qualifers of the argument, you'll need to overload it instead (because you can't partially specialize functions):
template <typename T>
requires std::same_as<int, std::remove_cvref_t<T>>
decltype(auto) f(T&& val) {return 42;}
Or:
decltype(auto) f(auto&& val)
requires std::same_as<int, std::remove_cvref_t<decltype(val)>>
{return 42;}