наследование — вызов неоднозначности шаблона базовой функции-члена в переполнении стека

Я пытаюсь реализовать поведение DependencyInjectable, и классы, производные от этого поведения, могут быть внедрены с соответствующими зависимостями при создании экземпляра.

Ниже я попытался извлечь и сжать пример кода из гораздо более крупного проекта, чтобы проиллюстрировать проблему, с которой я столкнулся. Это немного долго, и я прошу прощения за это.

#include <tuple>
#include <type_traits>

template <typename, typename> struct tuple_has_type;
template <typename T> struct tuple_has_type<T, std::tuple<>> : std::false_type { };
template <typename T, typename U, typename ... Args> struct tuple_has_type<T, std::tuple<U, Args ...>> : tuple_has_type<T, std::tuple<Args ...>> { };
template <typename T, typename ... Args> struct tuple_has_type<T, std::tuple<T, Args ...>> : std::true_type { };

template<typename ... Dependencies>
class DependencyInjectable
{
private:

template<int index, typename ... Args>
struct assign_dependencies
{
void operator () (std::tuple<Dependencies ...> &lhs, std::tuple<Args ...> &&rhs)
{
typedef typename std::tuple_element<index, std::tuple<Dependencies ...>>::type T;
std::get<T>(lhs) = std::get<T>(rhs);
assign_dependencies<index - 1, Args ...> { } (lhs, std::forward<std::tuple<Args ...>>(rhs));
}
};

template<typename ... Args>
struct assign_dependencies<0, Args ...>
{
void operator() (std::tuple<Dependencies ...> &lhs, std::tuple<Args ...> &&rhs)
{
typedef typename std::tuple_element<0, std::tuple<Dependencies ...>>::type T;
std::get<T>(lhs) = std::get<T>(rhs);
}
};

public:

template<typename ... Args>
DependencyInjectable(Args ... dependencies)
{
setDependencies(std::forward<Args>(dependencies) ...);
}

virtual ~DependencyInjectable(void) { }

template<typename T> auto getDependency(void) const ->
typename std::enable_if<tuple_has_type<T, std::tuple<Dependencies ...>>::value, T>::type
{
return std::get<T>(m_dependencies);
}

template<typename T, typename U = typename std::decay<T>::type>
auto setDependency(T &&dependency) ->
typename std::enable_if<tuple_has_type<U, std::tuple<Dependencies ...>>::value, void>::type
{
std::get<U>(m_dependencies) = dependency;
}

template<typename ... Args>
void setDependencies(Args ... dependencies)
{
constexpr auto size = std::tuple_size<std::tuple<Dependencies ...>>::value;
static_assert(size > 0, "List of dependencies must be specified.");
assign_dependencies<size - 1, Args ...> { } (m_dependencies, std::forward_as_tuple(
std::forward<Args>(dependencies) ...));
}

private:

std::tuple<Dependencies ...> m_dependencies; // an std::tuple containing injection dependencies
};

class DependencyOfBase { };
class DependencyOfDerived { };

class Base
: public DependencyInjectable<DependencyOfBase *>
{
public:

Base(DependencyOfBase *pDependencyOfBase)
: DependencyInjectable<DependencyOfBase *>(pDependencyOfBase)
{

}

virtual ~Base(void) { }
};

class Derived
: public Base, public DependencyInjectable<DependencyOfDerived *>
{
public:

using Base::getDependency;
using DependencyInjectable<DependencyOfDerived *>::getDependency;

Derived(DependencyOfBase *pDependencyOfBase, DependencyOfDerived *pDependencyOfDerived)
: Base(pDependencyOfBase),
DependencyInjectable<DependencyOfDerived *>(pDependencyOfDerived)
{

}

virtual ~Derived(void) { }
};

int main(int argc, char **argv)
{
DependencyOfBase dependencyOfBase;
DependencyOfDerived dependencyOfDerived;

Base base(&dependencyOfBase);
Derived derived(&dependencyOfBase, &dependencyOfDerived);

auto *pDependencyOfBase = base.getDependency<DependencyOfBase *>();
auto *pDependencyOfDerived = derived.getDependency<DependencyOfDerived *>();

return (pDependencyOfBase != nullptr && pDependencyOfDerived != nullptr) ? 0 : 1;
}

В частности, я использую std :: tuple для хранения зависимостей в классе DependencyInjectable, и я пытаюсь использовать enable_if для отключения функции getDependency (), когда кортеж не содержит запрошенный тип. В основном я вызываю экземпляр функции getDependency () Derived и указываю «DependencyOfDerived *». Это работает, пока я указываю

using Base::getDependency;
using DependencyInjectable<DependencyOfDerived *>::getDependency;

в классе Derived, но я бы подумал, что enable_if отключил бы функцию getDependency () в базе для параметра шаблона «DependencyOfDerived *», так как базовый кортеж не содержит этот тип. Что мне здесь не хватает?

Если я прокомментирую операторы using, я получу следующий вывод из gcc:

В функции ‘int main (int, char **)’:
116: 42: ошибка: запрос на член ‘getDependency’ является неоднозначным
45:31: примечание: кандидатами являются: шаблон typename std :: enable_if> :: value, T> :: type DependencyInjectable :: getDependency () const [with T = T; Зависимости = {DependencyOfDerived *}] 45:31: примечание: имя типа шаблона std :: enable_if> :: value, T> :: type DependencyInjectable :: getDependency () const [with T = T; Зависимости = {DependencyOfBase *}] 116: 76: ошибка: ожидаемое первичное выражение до маркера ‘*’
116: 77: ошибка: ожидаемое первичное выражение перед маркером ‘>’
116: 79: ошибка: ожидаемое первичное выражение до маркера ‘)’

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]