2

我正在阅读 C++ 中的“mixin”技术,但有一些我不明白的东西,似乎是语言的一个限制,由于编译器的歧义(和标准拒绝解决,甚至如果可以的话)。

mixin 的想法是聚合来自不同部分的能力。有时可以用相同的名称调用这些功能,因为它们通常做同样的事情。

struct A{
    void f(int){}
};

struct B{
    void f(double){}
};

我可以将这两个类的服务与

struct CombinedAB : A, B{};

但是,当我使用它时,我得到一个编译错误:“对成员 'f' 的请求不明确”(godbolt 链接)

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是静态函数,问题仍然存在。似乎该语言对更改或组合基类中成员函数的含义有强烈的感觉。

4

1 回答 1

1

我自己的问题的部分答案:

事实上,我意识到这是“点”符号的一个特性,以及 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)比强制符号更具限制性的第一种情况。我的结论是 mixins 不能通过“点”表示法工作。遗憾的是它也会影响静态成员函数(“::”符号)。f(c, a)

如果有人知道,我仍然会对使用“点”符号的一些技术感兴趣。

于 2020-09-30T19:13:08.977 回答