Учитывая структуру миксина шаблона C ++, как я могу написать функцию, которая принимает миксин с определенным компонентом? В этом примере, как я могу дать 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>>
против 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
называет другие типы. Следовательно:
WorksWithA
а также WorksWithB
для типа, переданного в WorksWithAAndB
,Вы должны сделать WorksWithA
шаблон функции; нет другого пути. Думаю об этом: WorksWithA
работает с любой тип, который имеет HasA
Mixin. Это можно выразить только с помощью шаблонов.
Также в случае HasA
а также HasB
имеют значение интерфейсов, рассмотрите возможность использования наследования для решения этой проблемы:
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++;
}
Здесь вы можете позвонить WorkWithA
с объектом любого класса, реализующего WithA
интерфейс и WorksWithAandB
с объектом любого класса реализации HasAB
интерфейс.
PS: к сожалению, в этом примере звонить невозможно WorksWithAandB
с объектом класса, реализующим оба HasA
а также HasB
без наследства от HasAB
, но это может быть решено с помощью шаблонов и SFINAE.