Мои общие элементы контейнера могут принимать любой класс, который соответствует определенным свойствам, и передает их, позволяя каждому экземпляру класса, приемлемого для Element, использовать свои собственные реализации требуемых функций.
На данный момент все поддерживаемые функции в Elements< Класс /code> предназначен для нешаблонных функций. Можно ли использовать подобный интерфейс со стиранием типов для поддержки шаблонных функций? В частности, мне нужна функция для преобразования между классами разных типов, которые содержатся в классе Elements.
Если мой интерфейс со стертым типом выглядит примерно так:
Код: Выделить всё
template
concept HasFoo = requires(T t) {
{ t.foo() } -> std::same_as;
};
template
concept IsUserDefinedElements = requires(T) {
// ... other generic requirement ... //
requires HasFoo;
};
struct ElementsInnerBase {
virtual ~ElementsInnerBase() {}
virtual int foo();
};
template
struct ElementsInner final : public ElementsInnerBase {
// Constructors from T (copy and move variants).
explicit ElementsInner(const T &x) : _value(x) {}
explicit ElementsInner(T &&x) : _value(std::move(x)) {}
// Invoke required methods directly
int foo() final {
return _value.foo();
}
// Elements object
T _value;
};
class Elements;
template
concept IsGenericallyConstructableElements = requires(T) {
requires IsUserDefinedElements;
std::negation::value;
};
class Elements {
public:
// Default constructor
Elements();
public:
template
requires(IsGenericallyConstructableElements)
explicit Elements(T &&x) :
_ptr(std::make_unique(std::forward(x)))
{}
// Foo
int foo() {
return _ptr->foo();
}
private:
// Pointer to the inner base elements
std::unique_ptr _ptr;
};
Код: Выделить всё
struct ElementsA {
int foo();
// ... A-specific details ... //
};
struct ElementsB {
int foo();
// ... B-specific details ... //
};
int run_foo(Elements e) { return e.foo(); }
int main() {
ElementsA a;
ElementsB b;
int aOut = run_foo(a);
int bOut = run_foo(b);
return 0;
}
Код: Выделить всё
template
T convert();
Код: Выделить всё
struct ElementsA {
int foo();
ElementsB convert() { ElementsB (*this); } // conversion could be arbitrarily complex
};
struct ElementsB {
int foo();
ElementsA convert() { ElementsA(*this); }
};
int some_process(Elements e) {
// ... generic processes on e ... //
ElementsB b = e.convert ();
// ... B-specific process ... //
}
int main() {
ElementsA a;
int aOut = some_process(a);
return 0;
}
Стирание типов важно в этом контексте, поскольку оно позволяет мне определить поведение по умолчанию для функций, которые пользователи могут не захотеть или не должны определять. И я мог бы просто добавить оболочки функций для вызовов функций конкретного типа, например ElementsB Convert_to_b() и т. д., но я надеялся сохранить интерфейс чистым и универсальным.
Подробнее здесь: https://stackoverflow.com/questions/793 ... s-from-a-p
Мобильная версия