Загадка проектирования кода: полиморфизм времени выполнения, шаблоны, время компиляции и OpenMPC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Загадка проектирования кода: полиморфизм времени выполнения, шаблоны, время компиляции и OpenMP

Сообщение Anonymous »

Я изо всех сил пытаюсь завершить проект моей библиотеки C++17.
Одна из основных целей — использовать полиморфизм во время выполнения, чтобы позволить пользователям расширять или переписывать функции библиотеки по умолчанию для своих собственных сценариев использования. Основная проблема заключается в том, что мне нужна иерархия полиморфизма, как в (сильно упрощенном) текущем дизайне ниже:

Код: Выделить всё

class SettingsBase
{
virtual OutType compute(InType var) = 0; // MODIFIES the object
};

class FeatureBase
{
virtual OutType compute(InType var) = 0;
};

class FeatureDefaultImpl: public FeatureBase
{
OutType compute(InType var) override
{
OutType settings_output = settings_->compute(some_var); // modifies settings_
// use settings_output in the remaining computations
}

// I want the settings themselves to be polymorphic in case the user wants to use
// FeatureDefaultImpl with their own settings class. So I use a constructor to pass
// in the settings.
template 
FeatureDefaultImpl(SettingsType& settings):
settings_(std::make_shared (settings)) {};

private:

std::shared_ptr settings_;
}
Примечание: FeatureDefaultImpl использует SettingsBase, но пользователь может написать свой собственный FeatureImpl, который НЕ использует SettingsBase , поэтому я не определил этот метод как

Код: Выделить всё

OutType compute(InType var, SettingsBase& settings) override
Этот дизайн сработал хорошо, потому что он избегает шаблонов (что я пробовал, но это привело к очень длительному времени компиляции), и он избавляет пользователя от необходимости иметь дело с указателями, в то же время внутренне используя полиморфизм, дружественный указателям во время выполнения (пользователи - это инженеры, привыкшие к Matlab, а указатели могут напугать тех, кто не привык к C/C++).
НО теперь я хочу сделать следующее:

Код: Выделить всё

void loop_function(FeatureDefaultImpl impl, int large_number)
{
#pragma omp parallel for firstprivate(impl)
for (int i = 0; i < large_number; ++i)
{
InType var; // = something
OutType output = impl.compute(var);
// store output in a matrix
}
}
Это дает мне неправильный ответ для более чем одного потока, поскольку у impl есть settings_, базовые данные которого он изменяет. Firstprivate просто создает копии settings_, но я думаю, что все потоки по-прежнему указывают на один и тот же объект.
Одно из решений, которое пришло мне в голову, — это определить мои собственные конструкторы перемещения и копирования, которые гарантируют, что settings_ всегда будет глубоко скопировано, но в библиотеке много таких базовых классов, и мне кажется немного неуклюжим добавлять весь дополнительный шаблонный код.
Другое решение: вместо этого просто сделать

Код: Выделить всё

template 
class FeatureDefaultImpl: public BaseFeatureA
{
OutType compute(InType var) override
{
OutType settings_output = settings_.compute(some_var);
// use settings_output in the remaining computations
}

FeatureDefaultImpl(SettingsType& settings):
settings_(settings) {};

private:

SettingsBase settings_;
}
что мне нравится, но когда я делаю это для всех производных классов и конвертирую файлы cpp в tpp, время компиляции становится огромным. Я думаю, причина в иерархической природе дизайна с большим количеством композиций, поэтому любой основной файл cpp в конечном итоге косвенно включает практически все заголовки библиотеки. Поэтому я не уверен, что даже предварительные декларации помогут.
  • Есть ли лучший способ добиться этих целей, чем варианты, которые я рассмотрел?
  • Если нет, то какой вариант наименее плохой с точки зрения передовой практики? То есть чем стоит пожертвовать?


Подробнее здесь: https://stackoverflow.com/questions/798 ... -and-openm
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»