Неоднозначность в устранении неоднозначности множественного наследования
При работе с множественным наследованием с использованием базовых классов шаблонов возникает потенциальная проблема, связанная с неоднозначным разрешением функций-членов. Рассмотрим следующий сценарий:
template
class Base {
public:
template
typename std::enable_if::value>::type foo() {
std::cout Здесь функция foo() доступна для вызова только в том случае, если параметр шаблона соответствует одному из типов в пакете типов. Теперь, если производный класс наследуется от нескольких базовых классов с непересекающимися наборами типов, компилятор может столкнуться с неоднозначностью при разрешении вызова foo().
struct Derived: public Base,
public Base
{};
В этом случае вызов Derived().foo() в идеале должен вызвать функцию-член foo() из Base. Однако и GCC, и Clang сообщают о двусмысленности.
Почему компилятор не может разрешить двусмысленность
Ошибка компиляции возникает из-за правил слияния для поиска функций-членов. Согласно стандарту C, если функция-член не объявлена в самом производном классе, процесс поиска по очереди ищет базовые классы. Однако если наборы объявлений в базовых классах различаются, слияние становится неоднозначным.
В данном сценарии производный класс Derived не объявляет foo() явно, поэтому компилятор должен объединить наборы поиска из два базовых класса. Поскольку базовые классы содержат разные наборы объявлений для foo(), слияние приводит к неоднозначности.
Решения
Чтобы разрешить эту двусмысленность, одним из вариантов является использование объявлений using в производном классе, чтобы явно импортировать нужные функции-члены. Однако для этого требуется, чтобы пользователь добавил эти объявления, что может быть многословным и непрактичным для больших списков типов.
struct Derived: public Base,
public Base
{
using Base::foo;
using Base::foo;
};
В качестве альтернативы можно использовать вспомогательный класс, который собирает и объединяет функции-члены из всех базовых классов, позволяя производному классу обращаться к ним напрямую.
template
struct BaseCollector : Bases...
{
using Bases::foo...;
};
struct Derived : BaseCollector , Base>
{};
При таком подходе пользователю не нужно добавлять какие-либо дополнительные объявления для устранения неоднозначности. Класс BaseCollector эффективно объединяет наборы объявлений всех базовых классов, делая функцию foo() доступной для производного класса без двусмысленности.
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3