Я использую библиотеку, когда многие классы написаны с помощью метода init (), возвращающего логическое значение. Я прочитал, что это позволяет вернуть код ошибки. В сигнатуре нет ничего общего (параметры могут быть любыми), но тип возвращаемого значения почти всегда bool, а имя функции всегда одно и то же, init. Аргументы могут быть любыми.
Пример:
class Handle {
Handle(const Handle&) = delete;
};
class BigResource {
BigResource(const BigResource&) = delete;
};
class A {
bool init(int, const BigResource&);
};
class B {
bool init(unsigned int, unsigned int, Handle&);
};
class D {
bool init();
}
class E {
bool init(const std::string&, const std::string&);
}
/* ... All classes are also not copyable */
Первый вопрос: я хотел бы использовать эти классы с контейнером. Условием является то, что я предполагаю, что все вызовы init () должны возвращать истину, а не то, что они всегда возвращают истину, но программа не работает, если какая-либо инициализация не работает (неисправимая ошибка, например, плохой mallo c или актив не найден). Я попытался обернуть все эти классы в другой, который обрабатывает инициализацию автоматически, но это невозможно, поскольку оператор преобразования не работает, потому что эти классы не копируются.
Итак, мне удалось использовать std :: generate для инициализации контейнеров STL с вызовом init () для каждого элемента. Теперь какова текущая проблема: я хотел бы иметь общий c класс генератора или функтор для инициализации всех элементов с одним и тем же аргументом, который может обрабатывать любой тип, уважающий ссылочные аргументы? std::bind
передаются по значениям, и я не знаю, можно ли использовать что-то вроде std::ref
с переменным c, при этом некоторые аргументы передаются по значению, а некоторые по ссылке.
What I пробовал сделать:
/**
* Functor to achieve the same effect but with a functor and stored arguments
*/
template<typename T> struct Creator
{
template<typename... Args>
Creator(Args&&... createArgs)
{
//m_callCreate = std::bind(create<T, Args...>, std::placeholders::_1, std::forward<Args>(createArgs)...); First test
m_callCreate = [&](T &obj) {
obj.init(std::forward<Args>(createArgs)...);
};
}
void operator()(T& t) {
m_callCreate(t);
}
private:
std::function<void(T&)> m_callCreate;
};
Работает? Я чувствую, что лямбда-захват приводит к висящей ссылке. Я пробовал также другие возможности (сохранить кортеж или std :: bind, завернутый в std :: function, которые выглядят так, как будто легко обертывают все аргументы, но я не знаю, какой метод лучше, и даже если это не UB. ) Я не очень понимаю эти функции и все возможные варианты поведения, но вкратце я хотел бы иметь такое же поведение, как если бы метод init был вызван напрямую, а именно:
- когда параметр ссылку, используйте ссылку (указанный объект должен существовать до последнего вызова operator ())
- , когда параметр является значением, и я чувствую, что вот настоящая проблема, захват по значению, например
int
(исходный объект может быть освобожден в конце конструктора)
Желаемое поведение:
// This code may be not possible
Handle handle;
std::vector<B> v(10, {1920, 1080, handle});
// Or at least:
Handle handle;
Generator<B> generator(1920, 1080, handle);
std::vector<B> v(10);
std::generate(v.begin(), v.end(), generator);