#c #templates
#c #шаблоны
Вопрос:
Есть ли способ сократить все операторы if constexpr, предполагая, что поиск буферов — это одно и то же поведение?
template <typename T>
struct Buffer
{};
struct BufferManager
{
Buffer<int> intBuffers[8];
Buffer<float> floatBuffers[8];
Buffer<char> charBuffers[8];
template <typename T>
static void uploadBuffer(int size, const T* data)
{
Buffer<T>* buffer = findSuitableBuffer<T>(size);
}
template<typename T>
static Buffer <T>* findSuitableBuffer(int size)
{
if constexpr (std::is_same_v<T, int>)
{
// SEARCH intBuffers FOR A SUITABLE BUFFER
}
else if constexpr (std::is_same_v<T, float>)
{
// SEARCH floatBuffers FOR A SUITABLE BUFFER
}
else if constexpr (std::is_same_v<T, char>)
{
// AND SO ON
} // DO I HAVE TO ADD ONE OF THESE EACH TIME I WANT TO ADD A TYPE?
Buffer<T> g{};
return amp;g;
}
};
Комментарии:
1. Знаете ли вы, что вы возвращаете временный адрес в конце функции? Кроме того, вы хотите выполнить поиск нестатического члена внутри статической функции. Это может привести к ошибке IMO.
2. Ах да, я забыл удалить, я избавлялся от ошибок компилятора, спасибо.
3. Если у вас есть
if
—else
construct, который предназначен для проверки типа чего-либо, у вас есть главный кандидат на полиморфную (не шаблонную) базу с (возможно) шаблонным классом, производным от этой базы и переопределяющим унаследованные виртуальные функции-члены.4. Вы можете использовать
std::tuple
для хранения всех ваших<T>Buffers
элементов данных, а затем вы можете использоватьstd::get<T>(<your tuple member>)
. Но, вероятно, вам нужно будет немного изменить свою архитектуру … чтобы все было правильно.5. Вам действительно нужны 3 отдельных буфера для начала?
Ответ №1:
Один из способов избавиться от if constexpr
— это сделать специализации findSuitableBuffer
, которые возвращают правильный массив буферов. Другой способ — findSuitableBuffer
полностью пропустить и сохранить буферы в кортеже.
Пример:
#include <cstddef>
#include <tuple>
struct BufferManager {
static constexpr size_t kBuffers = 8;
std::tuple<Buffer<int>[kBuffers],
Buffer<float>[kBuffers],
Buffer<char>[kBuffers]> Buffers;
template <typename T>
void uploadBuffer(const T* data, size_t size) {
autoamp; buffers = std::get<Buffer<T>[kBuffers]>(Buffers);
// SEARCH buffers FOR A SUITABLE BUFFER
for(size_t i = 0; i < kBuffers; i) {
if(buffers[i].has_room_for(size)) {
// ...
}
}
}
};
Ответ №2:
Не изменяя способ хранения ваших буферов, вы можете написать a findSuitableBuffer
, который принимает несколько разнородно типизированных буферов с помощью шаблона переменной рекурсивной функции…
template <typename T>
Buffer<T>amp; findSuitableBufferImpl(size_t size) {
throw std::runtime_error("not found");
}
template <typename T, typename U, typename...Ts, size_t I, size_t...Is>
Buffer<T>amp; findSuitableBufferImpl(size_t size, Buffer<U>(amp;buffer)[I], Buffer<Ts>(amp;...buffers)[Is]) {
if constexpr (std::is_same_v<T, U>) {
for (size_t i = 0; i < I; i ) {
if (/* test buffer[i] */) {
return buffer[i];
}
}
}
return findSuitableBufferImpl<T>(size, buffers...);
}
template <typename T>
Buffer<T>amp; findSuitableBuffer(size_t size) {
// Add types here
return findSuitableBufferImpl<T>(size, intBuffers, floatBuffers, charBuffers);
}
Демонстрация: https://godbolt.org/z/aYY4Ye
И, если бы вы могли использовать кортеж для хранения этих буферов, потребовалась бы небольшая корректировка:
template <typename... Ts>
struct BufferSet : std::tuple<Buffer<Ts>[8]...> {
using std::tuple<Buffer<Ts>[8]...>::tuple;
};
template <typename T, typename... Ts, size_t... Is>
constexpr Buffer<T> findSuitableBufferImpl(size_t size, BufferSet<Ts...>amp; buffers, std::index_sequence<Is...>) {
return findSuitableBufferImpl<T>(size, std::get<Is>(buffers)...);
}
template <typename T, typename... Ts>
constexpr Buffer<T> findSuitableBuffer(size_t size, BufferSet<Ts...>amp; buffers) {
return findSuitableBufferImpl<T>(size, buffers, std::index_sequence_for<Ts...>{});
}
// usage
BufferSet<int, double, char> buffers;
autoamp; buffer = findSuitableBuffer<double>(4, buffers);
Демонстрация: https://godbolt.org/z/v7PzGc
Комментарии:
1. Вау, этот рекурсивный пример потрясающий.