问题描述
我正在阅读有关C ++中的“ mixin”技术的信息,但是我不了解某些东西,并且由于限制了编译器(以及标准拒绝提供此类信息),该语言似乎受到限制,无法通用地执行此操作解决,即使可以)。
mixin的想法是聚合来自不同部分的功能。 有时,可以使用相同的名称来调用这些功能,因为它们通常会执行相同的操作。
struct A{
void f(int){}
};
struct B{
void f(double){}
};
我可以结合两个类的服务
struct CombinedAB : A,B{};
但是,当我使用它时,出现编译错误:"request for member ‘f’ is ambiguous" (godbolt link)。
CombinedAB c; c.f(3.14); // 3.14 is a double,I expect B::f to be called.
因此,编译器知道f
存在,但它拒绝来确定哪一个是正确的调用对象。它将产生此错误:
main.cpp: In function ‘int main()’:
main.cpp:23:21: error: request for member ‘f’ is ambiguous
CombinedAB c; c.f(3.14);
^
main.cpp:16:10: note: candidates are: void B::f(double)
void f(double){}
^
main.cpp:12:10: note: void A::f(int)
void f(int){}
^
我当然可以更改类,并使用此惯用法“带来f
重载的完整版本”。
struct CombineAB : A,B{
using A::f;
using B::f;
};
它可以工作,但是问题是CombineAB
无法通用完成。最接近的是:
template<class T1,class T2>
struct combination : T1,T2{
// using T1::all_provided_by_T1;
// using T2::all_provided_by_T2;
};
但是我不能不添加using T1::f; using T2::f
的等价物,首先是因为combination
需要了解T1,T2中所有可能的功能。
因此,似乎需要根据具体情况定义组合。例如,
template<class T1,class T2>
struct combination_of_f_service : T1,T2{
using T1::f; using T2::f;
}
这违反了目的,因为如果T1和T2提供20个具有相同名称的函数(在我的情况下),则该类将需要重复所有这些函数的名称。最糟糕的是无法通过其他模板参数来完成(可以吗?)。
这是在C ++中组合类的正确方法吗?是否有解决方法?或者这仅仅是问题的幼稚视图?如有必要,我愿意接受涉及很多模板代码的选项。
即使实例化不是方程式的一部分,并且f
是静态函数,问题仍然存在。
该语言似乎对在基类中更改或组合成员函数的含义有强烈的感觉。
解决方法
对我自己的问题的部分回答:
事实上,我意识到这是“点”符号的独特之处,并且C ++在使用此语法时有多坚定。 它似乎不是基本限制,而是该语言中专门用来限制点表示法使用的一个块。 也许这是与可能滥用虚拟功能有关的历史古怪。
我放开“点”表示法后,使用等效(但有些出乎意料)的语法突然可以实现mixin行为。
struct A{
void f(int){}
friend void f(A& self,int i){self.f(i);}
};
struct B{
void f(double){}
friend void f(B& self,double d){self.f(d);}
};
struct C : A,B{
// using A::f;
// using B::f;
};
template<class T1,class T2>
struct combination : T1,T2{};
int main(){
C c;
// c.f(5.1); // error,ambiguous call
f(c,5.1);
combination<A,B> c2;
f(c2,5.1);
}
有趣的是,如果此提案继续进行https://isocpp.org/blog/2016/02/a-bit-of-background-for-the-unified-call-proposal,则需要以某种方式解决此问题。
在第一种情况下,我看到强制使用符号c.f(a)
在根本上比限制使用f(c,a)
符号更严格。
我的结论是,mixins无法通过“点”表示法工作。
遗憾的是,它也会影响静态成员函数(“ ::”符号)。
如果有人知道,我仍然会对使用“点”表示法的某种技术感兴趣。