Я пытаюсь внедрить наивную систему GC для целей обучения.По сути, он предоставит пользователям интерфейс newElement
для «нового» объекта.
Стратегия, которую я хочу решить, состоит в том, чтобы выделить объект по другой стратегии (пул для небольшого объекта / malloc длябольшой ...) в соответствии с типом объекта, например:
T* newElement(Args&&... args)
{
if(sizeof(T) < 4){
// strategy1
return newImpl1(std::forward<Args>(args)...);
} else if(4 <= sizeof(T) < 16){
// strategy2
return newImpl2(std::forward<Args>(args)...);
} else{
// strategy3
return newImpl3(std::forward<Args>(args)...);
}
}
я думаю, что эта стоимость может быть во время компиляции, но не во время выполнения, так как sizeof(T)
может быть оценена во время компиляции.Я знаю, что в C ++ 17 у нас есть такие функции, как constexpr if
для решения подобных ситуаций.Тем не менее, я имею дело с VS 2015, он поддерживает только C ++ 11 и C ++ 14.Итак, я рассматриваю процесс как две разные фазы:
«новый» должен принимать разные виды меток (по типу) для разрешения другой стратегии
«диспетчеризация» должна принимать T в качестве входных данных и иметь способ для вывода правильной метки (по типу)
Как правило, целью фазы 2 является вывод различных типовметки (независимо от значений или типов) с помощью ряда условных выражений.
На ум приходят два вида решений.
enum class Strategy {
small, middle, big
};
constexpr size_t SmallMiddleThreshold = 4;
constexpr size_t MiddleBigThreshold = 8;
template
<Strategy s=Strategy::small>
struct newImpl {
template
<typename T, typename... Args>
static T* apply(Args&&... args)
{
cout << "small!" << endl;
return new T(std::forward<Args>(args)...);
}
};
template
<>
struct newImpl<Strategy::middle> {
template
<typename T, typename... Args>
static T* apply(Args&&... args)
{
cout << "middle!" << endl;
return new T(std::forward<Args>(args)...);
}
};
template
<>
struct newImpl<Strategy::big> {
template
<typename T, typename... Args>
static T* apply(Args&&... args)
{
cout << "big!" << endl;
return new T(std::forward<Args>(args)...);
}
};
Решение 1
используйте шаблоны переменных для расширения условных выражений.
template
<bool Condition1=true, bool... Conditions>
struct SizeDispatcher1 {
constexpr static Strategy value = Strategy::small;
};
template
<bool... Conditions>
struct SizeDispatcher1<false, Conditions...> {
constexpr static Strategy value = SizeDispatcher2<Conditions...>::value;
};
template
<bool Condition2 = true, bool... Conditions>
struct SizeDispatcher2 {
constexpr static Strategy value = Strategy::middle;
};
template
<bool... Conditions>
struct SizeDispatcher2<false, Conditions...> {
constexpr static Strategy value = SizeDispatcher3<Conditions...>::value;
};
template
<bool Condition3 = true, bool... Conditions>
struct SizeDispatcher3 {
constexpr static Strategy value = Strategy::big;
};
template
<typename T>
struct SizeDispatcher {
constexpr static Strategy value =
SizeDispatcher1<
sizeof(T) < SmallMiddleThreshold,
SmallMiddleThreshold <= sizeof(T) && sizeof(T) < MiddleBigThreshold,
MiddleBigThreshold <= sizeof(T)
>::value;
};
template
<typename T, typename... Args>
T* newElement(Args&&... args)
{
return newImpl<SizeDispatcher<T>::value>::apply<T>(std::forward<Args>(args)...);
}
Решение 2
используйте частичную специализацию для сопоставления различных случаев.
template
<bool Condition1=true, bool Condition2=false, bool Condition3=false>
struct SizeDispatcherImpl {
constexpr static Strategy value = Strategy::small;
};
template
<>
struct SizeDispatcherImpl<false, true, false> {
constexpr static Strategy value = Strategy::middle;
};
template
<>
struct SizeDispatcherImpl<false, false, true> {
constexpr static Strategy value = Strategy::big;
};
template
<typename T>
struct SizeDispatcher {
constexpr static Strategy value =
SizeDispatcherImpl<
sizeof(T) < SmallMiddleThreshold,
SmallMiddleThreshold <= sizeof(T) && sizeof(T) < MiddleBigThreshold,
MiddleBigThreshold <= sizeof(T)
>::value;
};
Однако яУ меня есть вопросы по поводу приведенного выше кода.
Во-первых, может ли он правильно выполнить мое требование?То есть, чтобы разрешить разные стратегии во время компиляции?
Во-вторых, оба решения имеют как минимум следующие недостатки: 1. Диспетчер тесно связан с условными выражениями (формат, последовательность ...), что определенно не является хорошей практикой кодирования.2. не имеют четкой семантики.
Итак, как правильно и лучше решить вопрос, если это возможно? (Для создания другой метки с помощью серии условных выражений)