4

我目前正在实现一个基于元编程的小型编译时计算库。

如果已经为运算符定义了一个基类,它有一个结果 typedef(我决定使用整数包装器,例如std::integral_constant作为值而不是原始整数值,以提供沿库的统一接口)和一个 n 元运算符基类,检查运算符是否至少有一个操作数:

template<typename RESULT>
struct operator
{
    using result = RESULT;
};

template<typename RESULT , typename... OPERANDS>
struct nary_operator : public operator<RESULT>
{
    static_assert( sizeof... OPERANDS > 0 , "An operator must take at least one operand" );
};

所以我为一元和二元运算符定义了别名:

template<typename OP , typename RESULT>
using unary_operator = nary_operator<RESULT , OP>;

template<typename LHS , typename RHS , typename RESULT>
using binary_operator = nary_operator<RESULT , LHS , RHS>;

该运算符接口用于将自定义运算符定义为别名,例如下面的比较运算符:

template<typename LHS , typename RHS>
using equal = binary_operator<LHS,RHS,bool_wrapper<LHS::value == RHS::value>>;

template<typename LHS , typename RHS>
using not_equal = logical_not<equal<LHS,RHS>>;

template<typename LHS , typename RHS>
using less_than = binary_operator<LHS,RHS,bool_wrapper<LHS::value < RHS::value>>;

template<typename LHS , typename RHS>
using bigger_than = less_than<RHS,LHS>;

template<typename LHS , typename RHS>
using less_or_equal = logical_not<bigger_than<LHS,RHS>>;

template<typename LHS , typename RHS>
using bigger_or_equal = logical_not<less_than<LHS,RHS>>;

现在假设我们想为我们自己的类实现我们的自定义相等运算符。例如:

template<typename X , typename Y , typename Z>
struct vec3
{
    using x = X;
    using y = Y;
    using z = Z;
}; 

如果相等运算符是在继承时创建的,而不是别名,则可以通过模板特化轻松完成:

//Equality comparator implemented through inheritance:
template<typename LHS , typename RHS>
struct equal : public binary_operator<LHS,RHS,bool_wrapper<LHS::value == RHS::value>> {};

//Specialization of the operator for vec3:

template<typename X1 , typename Y1 , typename Z1 , typename X2 , typename Y2 , typename Z2>
struct equal<vec3<X1,Y1,Z1>,vec3<X2,Y2,Z2>> : public binary_operator<vec3<X1,Y1,Z1>,vec3<X2,Y2,Z2> , bool_wrapper<X1 == X2 && Y1 == Y2 && Z1 == Z2>> {}; 

我知道模板别名不能专门化
我的问题是:有没有办法不使用继承设计而不是模板别名来专门化这种模板别名?

4

3 回答 3

5

我用来专门化模板别名(或提供递归别名)的模式是有一个相应的 _impl 结构。例如:

template <typename T>
struct my_alias_impl { /* def'n */ };

template <>
struct my_alias_impl<int> { /* alternate def'n */ };

template <typename T>
using my_alias = my_alias_impl<T>;

用户将不得不专注于 my_alias_impl,但公共接口的其余部分保持干净。

于 2013-07-24T19:41:51.170 回答
2

我知道这是一个老问题,但这是一个常见问题,到目前为止,在这个线程中还没有令人满意的答案......所以我会尝试给出一个 - 它解决了一般问题而不是具体问题(请注意需要 C++14)。

namespace impl
{
    template<typename ... Args> struct A;
    template<typename T> struct A<T>
    {
        A() {std::cout<<"I'm an A"<<std::endl;}
    };

    template<typename ... Args> struct B;
    template<typename T, typename V> struct B<T, V>
    {
        B() {std::cout<<"I'm a B"<<std::endl;}
    };
}

template<typename ... Args>
using C = std::conditional_t<sizeof...(Args)==1
                          , typename impl::A<Args ...>
                          , typename impl::B<Args ...> >;

int main()
{
    C<double> a;            //prints "I'm an A"
    C<double, int> b;       //prints "I'm a B"
}

演示

代码应该是不言自明的:主要思想是根据参数的数量静态选择类型。Aand的可变参数声明B是必要的,否则编译器会抱怨它不能B用单个参数实例化 a 或A用两个参数分别实例化 a 。

这种方法肯定不是完全通用的——想想默认参数或特殊化B——但也许它也可以扩展以处理这种情况。尽管如此,我发现它有时在我的编码中很有用。

于 2015-03-28T11:13:51.977 回答
0

类型别名不能专门化,但如果您的目标是在语法上简化特征,那么您可以像我一样做。我将相关的特征组合在一个 blob 中,它是一个反模式,但是我使用 blob 本身的继承而不是专门化来覆盖一个特征

#define DEFINE_TRAIT(TraitClass,TraitName)                             \
template<typename... T> using TraitName = typename TraitClass<T...>::TraitName

DEFINE_TRAIT(BinaryOpTrait, equal);
DEFINE_TRAIT(BinaryOpTrait, not_equal);
...
...

template<typename LHS , typename RHS>
struct BinaryOpTraitBase
{
    using equal = binary_operator<LHS,RHS,bool_wrapper<LHS::value == RHS::value>>;
    using not_equal = logical_not<::equal<LHS,RHS>>;
    ...
    ...
};
template<typename LHS , typename RHS>
struct BinaryOpTrait : BinaryOpTraitBase <LHS, RHS> {};

typename<>
struct BinaryOpTrait<vec3, vec3> : BinaryOpTraitBase<vec3, vec3>
{
    using equal = /* custom op */
};


//Usage:
    if(equal<int,int>(1,1))
        ...
    if(equal<vec3,vec3>(v1,v1)  //uses specialized
        ...
于 2013-07-26T02:13:22.270 回答