获得std :: multiply和std :: plus的中性元素

时间:2012-10-17 09:01:01

标签: c++ stl template-meta-programming

实现构造函数采用的模板类时:

  1. 函数向量(函数类型为std::function<bool(const T&)>
  2. std::binary_function<bool,bool,bool>我将用于累积从1)到某个值的矢量应用结果。
  3. 我希望能够使用std::plus()std::multiplies()作为第二个模板参数,但问题是根据函数我需要一个相应的中性元素(对于std累积初始值)。对于ANDstd::multiplies)我需要true(又名1),ORstd::plus)我需要false(又名0)。我知道我可以专门化模板并解决问题,但我想知道是否有办法为内置STL函数获取中性元素。

3 个答案:

答案 0 :(得分:6)

如果您使用的是gcc,则可以使用__gnu_cxx::identity_element,这正是您所要求的。

如果你不是,我认为没有一般的解决方案,好像有,gcc不会实现自己的 - 你可能只是重写他们的实现(实际上只是一个一些模板专业化,如你所料)。

编辑:此代码的源代码位于this file的第78-98行。

答案 1 :(得分:4)

这里通常的解决方案是特质。而不是实例化你的 std::plus上的模板或者其他什么,你可以在a上实例化它 traits类,为typedef定义std::plus,加上 identity元素(static const,with initializer),以及其他任何东西 需要。类似的东西:

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

在这两种情况下,当然,你必须提供所有必要的 traits,作为独立类或模板特化。 如果您需要的唯一两个标识元素是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;
};

这将 not 在C ++ 11之前工作,因为Op(1, 0)不是常数 epxression。我不确定C ++ 11;但我认为如果 Op::operator()被声明为constexpr,它应该有效。 (我只会 如果我不得不覆盖很多运营商,包括其中一些运营商,那就太费劲了 客户可能会提供。)

答案 2 :(得分:3)

从詹姆斯的答案(以及我对它的评论)中找出一点。我认为值得单独考虑。

如果您愿意,可以在运行时计算身份,假设确实存在身份。它是!func(true, false)

如果func::operator()可用并且没有副作用,就像std::plusstd::multiplies一样,那么可能任何合理的编译器都会在编译时实际计算出来。但它在编译时不需要该值,因此现在您的模板可以(如果调用者想要的话)接受std::function<bool(bool,bool)>而不需要在编译时知道实际的累积操作。