这里通常的解决方案是特征。与其实例化您的模板或其他任何东西,不如std::plus
在一个特征类上实例化它,该类定义了一个typedef
for std::plus
,加上一个标识元素(静态 const,带初始化器)以及您需要的任何其他东西。就像是:
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)
不是一个常量表达式。我不确定 C++11;但我认为如果
Op::operator()
声明constexpr
,它应该工作。(如果我必须涵盖很多运营商,包括客户可能提供的一些运营商,我只会费心尝试。)