Функция по умолчанию, которая возвращает только прошедшее значение?

Как ленивый разработчик, мне нравится использовать этот трюк, чтобы указать функцию по умолчанию:

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

Но у меня есть проблема в очень конкретном случае, которая заключается в следующем:

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

В этом случае я хотел бы, чтобы функция по умолчанию была эквивалентной: [](const unsigned int i){return i;} (функция, которая просто возвращает переданное значение).

Чтобы сделать это, что мне нужно написать вместо /*SOMETHING 1*/ и /*SOMETHING 2*/?

Ответ 1

Нет стандартного функтора, который делает это, но его достаточно легко написать (хотя конкретная форма для некоторого спора):

struct identity {
    template<typename U>
    constexpr auto operator()(U&& v) const noexcept
        -> decltype(std::forward<U>(v))
    {
        return std::forward<U>(v);
    }
};

Это можно использовать следующим образом:

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

Ответ 2

boost:: phoenix предлагает полный функциональный набор инструментов, здесь 'arg1' является идентификатором идентификатора; -)

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

Ответ 3

Это называется identity. К сожалению, он не является частью стандарта С++, но вы можете легко создать его самостоятельно.

Если вы используете g++, вы можете активировать его расширения с помощью -std=gnu++11, а затем

#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 = __gnu_cxx::identity<Type>())
{
    for (unsigned int i = 0; i < Size; ++i) {
        x[i] = f(i);
    }
}

Ответ 4

Вы можете просто создать свой собственный функтор идентификации:

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