получение нейтрального элемента для std :: multiply и std :: plus

При реализации шаблонного класса, конструктор которого принимает:

  1. вектор функций (функции имеют тип std::function<bool(const T&)>)
  2. std::binary_function<bool,bool,bool> что я буду использовать, чтобы накапливать результаты применений вектора от 1) до определенного значения.

Я хочу быть в состоянии использовать std::plus() а также std::multiplies() в качестве второго параметра шаблона, но проблема в том, что в зависимости от функции мне нужен соответствующий нейтральный элемент (для std накапливается значение init). За AND (std::multiplies) Я нуждаюсь true (ака 1), за OR (std::plus) Я нуждаюсь false (ака 0). Я знаю, что могу просто специализировать шаблон и решить проблему, но мне интересно, есть ли способ получить нейтральный элемент для встроенной функции STL.

3

Решение

Если вы используете gcc, ты можешь использовать __gnu_cxx :: identity_element, который делает именно то, что вы просите.

Если нет, я не думаю, что есть общее решение, как если бы оно было, gcc не реализовали бы их собственные — вы могли бы просто переписать их реализацию (что, как вы и ожидали, на самом деле всего лишь пара специализаций шаблонов).

Изменить: исходный код для этого находится в строках 78-98 этот файл.

6

Другие решения

Обычное решение здесь — черты. Вместо того, чтобы создавать ваши экземпляры
шаблон на std::plus или что-то еще, вы бы создали его на
класс черт, который определяет typedef за std::plusплюс
элемент тождества (статический констант, с инициализатором) и все остальное, что вы
необходимость. Что-то вроде:

struct OpTraitsAdd
{
typedef std::plus<int> Op;
static int const identity = 0;
};

struct OpTraitsMult
{
typedef std::multiplies<int> Op;
static int const identity = 1;
};

Также возможно получить черты от стандартного оператора,
используя явную специализацию:

template <typename Op> struct OpTraits;
template<>
struct OpTraits<std::plus<int> >
{
static int const identity = 0;
};
template<>
struct OpTraits<std::multiplies<int> >
{
static int const identity = 1;
};

В этом случае вы должны создать экземпляр своего класса с помощью оператора и
использование OpTraits<Op>::identity при необходимости.

В обоих случаях, конечно, вы должны предоставить все необходимое
черты, или как независимые классы или как шаблонные специализации.
Если вам нужны только два идентифицирующих элемента 0 и 1, вы можете
в состоянии сделать это автоматически с чем-то вроде:

template <bool idIs0> struct IdImpl;
template<>
struct IdImpl<false>
{
static int value = 1;
};
template<>
struct IdImpl<true>
{
static int value = 0;
};

template <typename Op>
struct Id
{
static int value = ItImpl<Op(1, 0) == 1>::value;
};

Это будет не работа до C ++ 11, так как Op(1, 0) не является константой
epxression. Я не уверен насчет C ++ 11; но я думаю, что если
Op::operator() объявлен constexpr, он должен работать. (Я бы только
пытаться, если бы мне пришлось охватить много операторов, в том числе те, которые
клиенты могут предоставить.)

4

Просто чтобы выделить один пункт из ответа Джеймса (и мой комментарий к нему). Я думаю, что это заслуживает отдельного рассмотрения.

Если вы хотите, вы можете вычислить идентичность во время выполнения, предполагая, что она действительно существует. Это !func(true, false),

Если func::operator() доступно и без побочных эффектов, как это для std::plus а также std::multipliesто, вероятно, любой разумный компилятор фактически вычислит это во время компиляции. Но это не требует значения во время компиляции, так что теперь ваш шаблон может (если вызывающий хочет) принять std::function<bool(bool,bool)> вместо того, чтобы знать фактическую операцию накопления во время компиляции.

3
По вопросам рекламы [email protected]