将类mixins的功能与歧义调用结合起来

问题描述

我正在阅读有关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无法通过“点”表示法工作。 遗憾的是,它也会影响静态成员函数(“ ::”符号)。

如果有人知道,我仍然会对使用“点”表示法的某种技术感兴趣。