如何将模板mixin作为参数

How to take template mixin as argument?

本文关键字:参数 mixin      更新时间:2023-10-16

考虑一个c++模板mixin结构,我如何编写一个带有特定组件的mixin的函数?在本例中,如何将withAandB赋给worksWithA() ?

struct Base {};
template <class T>
struct HasA : T
{
    int A;
};
template <class T>
struct HasB : T
{
    int B;
};
void WorksWithA(HasA<Base> &p)
{
    p.A++;
}
void WorksWithAandB(HasA<HasB<Base> > &p)
{
    p.A++;
    p.B++;
}
int _tmain(int argc, _TCHAR *argv[])
{
    HasA<Base> withA;
    HasA<HasB<Base> > withAandB;
    WorksWithA(withA); // OK
    WorksWithAandB(withAandB); // OK
    WorksWithA(withAandB); // KO, no conversion available
    return 0;
}

即使不考虑构造问题,或者混合排序(HasA<HasB<Base>> vs HasB<HasA<Base>>),我也看不到一个好的方法来编写这个函数,除了使它成为一个模板之外。

我目前在一个没有c++ 11的环境中,但如果现代c++提供了一个解决方案,我很感兴趣。

非常感谢!

你可以使WorksWithA成为一个模板函数,它接受任何用HasA包装的类:

template<typename T>
void WorksWithA(HasA<T> &p)
{
  p.A++;
}

在这种情况下,代码编译没有错误。

我认为你必须使你的函数模板,以及?

template <class T>
void WorksWithA(HasA<T> &p)
{
    p.A++;
}
template <class T>
void WorksWithAandB(HasA<HasB<T> > &p)
{
    p.A++;
    p.B++;
}

由于HasA<HasB<Base>>无法转换为HasA<Base> .

正如其他人指出的那样,这些函数作为模板可能更好。然而,当你在做的时候,你也可以删除一些重复的代码:

template<class B> 
void WorksWithA(HasA<B> &p) 
{ 
    p.A++; 
} 
template<class B> 
void WorksWithB(HasA<B> &p) 
{ 
    p.B++;
}
template<class Has>
void WorksWithAandB(Has &p)
{
    WorksWithA(p);
    WorksWithB(p);
}

这里WorksWithAAndB调用其他类型。因此:

  1. 您正在重用代码。
  2. 对于传递给WorksWithAAndB的类型,您正在重用编译器对传递给WorksWithAWorksWithB的类型类型的检查。

你必须让WorksWithA成为一个函数模板;没有别的办法。想想看:WorksWithA可以与任何具有HasA mixin的类型一起工作。

同样,在HasAHasB具有接口含义的情况下,可以考虑使用继承来解决这个问题:

struct HasA
{
  int A;
  virtual ~HasA() = default;
};
struct HasB
{
  int B;
  virtual ~HasB() = default;
};
struct HasAB : HasA, HasB
{
};
struct Base : HasAB
{};
void WorksWithA(HasA &p)
{
  p.A++;
}
void WorksWithAandB(HasAB &p)
{
  p.A++;
  p.B++;
}

这里可以用实现WithA接口的任何类的object调用WorkWithA,也可以用实现HasAB接口的任何类的object调用WorksWithAandB

PS:不幸的是,在这个例子中,不可能用实现HasAHasB的类的对象调用WorksWithAandB而不继承HasAB,但这可以使用模板和SFINAE来解决。