As a lazy developer, I like to use this trick to specify a default function:
template <class Type, unsigned int Size, class Function = std::less<Type> >
void arrange(std::array<Type, Size> &x, Function&& f = Function())
{
std::sort(std::begin(x), std::end(x), f);
}
But I have a problem in a very particular case, which is the following:
template <class Type, unsigned int Size, class Function = /*SOMETHING 1*/>
void index(std::array<Type, Size> &x, Function&& f = /*SOMETHING 2*/)
{
for (unsigned int i = 0; i < Size; ++i) {
x[i] = f(i);
}
}
In this case, I would like the default function to be the equivalent of: [](const unsigned int i){return i;}
(a function that just returns the passed value).
In order to do that, what do I have to write instead of /*SOMETHING 1*/
and /*SOMETHING 2*/
?
There is no standard functor that does this, but it is easy enough to write (though the exact form is up for some dispute):
struct identity {
template<typename U>
constexpr auto operator()(U&& v) const noexcept
-> decltype(std::forward<U>(v))
{
return std::forward<U>(v);
}
};
This can be used as follows:
template <class Type, std::size_t Size, class Function = identity>
void index(std::array<Type, Size> &x, Function&& f = Function())
{
for (unsigned int i = 0; i < Size; ++i) {
x[i] = f(i);
}
}
boost::phoenix offers a complete functional toolbox, here 'arg1' is the ident to identity ;-)
#include <boost/phoenix/core.hpp>
template <class X, class Function = decltype(boost::phoenix::arg_names::arg1)>
void index(X &x, Function f = Function()) {
for (std::size_t i = 0; i < x.size(); ++i) {
x[i] = f(i);
}
}
This is called the identity
function. Unfortunately, it is not part of the C++ standard, but you can easily build one yourself.
If you happen to use g++, you can activate its extensions with -std=gnu++11
and then
#include <array>
#include <ext/functional>
template <class Type, std::size_t Size, class Function = __gnu_cxx::identity<Type> >
void index(std::array<Type, Size> &x, Function&& f = Function())
{
for (unsigned int i = 0; i < Size; ++i) {
x[i] = f(i);
}
}
Maybe it will be available in C++20, see std::identity
. Until then you may look at boost's version at boost::compute::identity.
You can just build your own identity functor:
template <typename T>
class returnIdentifyFunctor
{
public:
auto operator ()( T &&i ) -> decltype( std::forward<T>(i) )
{
return std::move(i);
}
};
template <class Type, unsigned int Size, class Function = returnIdentifyFunctor<Type>>
void index(std::array<Type, Size> &x, Function&& f = Function() )
{
for (unsigned int i = 0; i < Size; ++i) {
x[i] = f(i);
}
}
A way to deal with this is to have two different functions. I find quite sane not to use default parameters.
template <class Type, unsigned int Size, class Function>
void index(std::array<Type, Size> &x, Function&& f){
for(unsigned int i = 0; i < Size; ++i) x[i] = f(i);
}
template<class Type, unsigned int Size>
void index(std::array<Type, Size> &x){
return index(x, [](unsigned int i){return i;}); // C++11 in this case
//, [](auto&& e){return std::forward<decltype(e)>(e)};); // C++14 in a more general case
//, std::identity); // C++20 in general
}