При реализации шаблонного класса, конструктор которого принимает:
std::function<bool(const T&)>
)std::binary_function<bool,bool,bool>
что я буду использовать, чтобы накапливать результаты применений вектора от 1) до определенного значения.Я хочу быть в состоянии использовать std::plus()
а также std::multiplies()
в качестве второго параметра шаблона, но проблема в том, что в зависимости от функции мне нужен соответствующий нейтральный элемент (для std накапливается значение init). За AND
(std::multiplies
) Я нуждаюсь true
(ака 1
), за OR
(std::plus
) Я нуждаюсь false
(ака 0
). Я знаю, что могу просто специализировать шаблон и решить проблему, но мне интересно, есть ли способ получить нейтральный элемент для встроенной функции STL.
Если вы используете gcc
, ты можешь использовать __gnu_cxx :: identity_element, который делает именно то, что вы просите.
Если нет, я не думаю, что есть общее решение, как если бы оно было, gcc
не реализовали бы их собственные — вы могли бы просто переписать их реализацию (что, как вы и ожидали, на самом деле всего лишь пара специализаций шаблонов).
Изменить: исходный код для этого находится в строках 78-98 этот файл.
Обычное решение здесь — черты. Вместо того, чтобы создавать ваши экземпляры
шаблон на 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
, он должен работать. (Я бы только
пытаться, если бы мне пришлось охватить много операторов, в том числе те, которые
клиенты могут предоставить.)
Просто чтобы выделить один пункт из ответа Джеймса (и мой комментарий к нему). Я думаю, что это заслуживает отдельного рассмотрения.
Если вы хотите, вы можете вычислить идентичность во время выполнения, предполагая, что она действительно существует. Это !func(true, false)
,
Если func::operator()
доступно и без побочных эффектов, как это для std::plus
а также std::multiplies
то, вероятно, любой разумный компилятор фактически вычислит это во время компиляции. Но это не требует значения во время компиляции, так что теперь ваш шаблон может (если вызывающий хочет) принять std::function<bool(bool,bool)>
вместо того, чтобы знать фактическую операцию накопления во время компиляции.