【问题标题】:getting an neutral element for std::multiply and std::plus获得 std::multiply 和 std::plus 的中性元素
【发布时间】:2012-10-17 09:01:01
【问题描述】:

在实现模板类时,其构造函数采用:

  1. 函数向量(函数类型为std::function<bool(const T&)>
  2. std::binary_function<bool,bool,bool> 用于将向量应用的结果从 1) 累积到某个值。

我希望能够使用std::plus()std::multiplies() 作为第二个模板参数,但问题是根据函数我需要一个相应的中性元素(用于std 累积初始值)。对于ANDstd::multiplies)我需要true(又名1),对于ORstd::plus)我需要false(又名0)。我知道我可以专门化模板并解决问题,但我想知道是否有办法为内置的 STL 函数获取中性元素。

【问题讨论】:

  • FWIW 在数学中,“中性元素”被称为“身份元素”,或者只是“身份”。因此,0 是“加法身份”,1 是字段模 2 中的“乘法身份”。
  • 你想要某种通用的中性元素,独立于 AND 或 OR,本地专业化?你能提供一个使用例子吗?
  • @SteveJessop 在我的国家很抱歉(在谈到群论时),我们称之为字面意思是英语中的中性元素。很抱歉造成混乱。
  • @Acorbe 就像例子说我想“乘积”或“加积”,其中乘或加是模板参数,所以我需要从加到 0 和从乘到 1 的映射.
  • 在 Stepanov 的一本书中,我想我看到了在函数调用 template<class Operator, class T> void function(Operator op, T x, T y, T op_identity){...} 中将标识元素作为额外参数传递的代码。有时这可能是一种解决方法(因为调用者可能知道什么是 Operator 类型)。

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


【解决方案1】:

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

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

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

【讨论】:

  • 我没有使用 gcc,我在 VC10 上,但是很好的信息。 :D
  • 另外,在 STLab 中,stlab.adobe.com/…
【解决方案2】:

这里通常的解决方案是特征。而不是实例化你的 std::plus 或其他上的模板,您可以在 特征类,它为std::plus 定义了一个typedef,加上一个 标识元素(静态常量,带初始化器),以及其他任何你 需要。比如:

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&lt;Op&gt;::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) 不是常量 表达。我不确定 C++11;但我认为如果 Op::operator() 被声明为 constexpr,它应该可以工作。 (我只会 如果我必须涵盖很多运营商,包括一些 客户可能会提供。)

【讨论】:

  • 在结尾处表达聪明部分的另一种方式是假设Op 有一个身份,那么在bool 中身份是!(Op(true,false))。因为如果a*b == a 那么b 就是身份,如果a*b == b 那么a 就是身份。不过,这确实依赖于Op 满足组操作的要求。如果用户提供一个将任何输入映射到0 的操作,那么它没有标识,因此自动检测会猜错并继续,而特征方法可能无法编译,因为不会有适合Op 的专业化。
  • 有了这些信息,您可以在 C++03 中运行时计算身份。
【解决方案3】:

只是从詹姆斯的回答中挑出一点(以及我对此的评论)。我认为值得单独考虑。

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

如果func::operator() 可用并且没有副作用,就像std::plusstd::multiplies 一样,那么大概任何明智的编译器都会在编译时实际计算它。但它在编译时不需要该值,所以现在您的模板可以(如果调用者想要)接受std::function&lt;bool(bool,bool)&gt;,而不需要在编译时知道实际的累加操作。

【讨论】:

    猜你喜欢
    • 2022-10-25
    • 2022-08-12
    • 2019-09-21
    • 1970-01-01
    • 2021-11-06
    • 2011-03-18
    • 2018-01-11
    • 2022-10-24
    • 1970-01-01
    相关资源
    最近更新 更多