Передача данных через аргумент шаблона, C++

Я думаю о том, чтобы в моей программе были структуры цветовых пространств. Теперь, как вы можете видеть, каждое цветовое пространство имеет свои ограничения для каждого из его компонентов. Итак, рассмотрим такую ​​структуру.

template<typename T>
struct SomeColorSpace{
    T component1,component2,.....; // or std::array<T,N> components, N is compile-time const
};

Теперь мне нужно как-то определить диапазон, поэтому я создаю структуру.

template<typename T>
struct Range{

    T min, max;

    // Some constructors initializing min and max...
};

Теперь мне нужно, чтобы моя структура цветового пространства знала, каков диапазон каждого ее компонента. Но, как видите, я не могу просто хранить std::array<Ranges<T>,N> ranges в своей структуре, так как диапазоны различаются от типа к типу. В качестве примера рассмотрим struct RGB каждый из компонентов может быть float или unsigned char, поэтому, когда компоненты float, диапазоны каждого компонента становятся [0,1];, а когда это беззнаковый символ, это [0,255];. Написание специализации шаблона для каждого из этих случаев является решением, но вместо этого я хочу подобную подпись. using RGBFloat = RGB<float,Range<float>...>. Я имею в виду, что хочу передать диапазоны через пакет параметров шаблона. Я знаю, что, например, Range<float>(0,1); — это параметр шаблона, не являющийся типом, поэтому одним из обходных путей является рефакторинг struct Range следующим образом.

template<typename T,T _MIN, T _MAX>
struct Range{
    static constexpr T MIN = _MIN;
    static constexpr T MAX = _MAX;
};

Таким образом, я могу передать Range<T,T min, T max> как пакет параметров шаблона, но тогда мне нужно сохранить пакет в std::tuple (я этого тоже не хочу). Мой вопрос: видите ли вы какую-либо другую возможность с помощью рефакторинга структуры Range или чего-то еще, чтобы иметь эту сигнатуру определения цветового пространства. using DefineColorSpace = ColorSpace<unsigned char, ranges....>. Я знаю, что в C++ 20 есть огромные рефакторинги для нетиповых параметров шаблона, но я использую clang, и кажется, что они пока не поддерживают эту функцию. Любой совет может быть полезен, спасибо)

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поддержка литеральных классов в качестве параметра шаблона, отличного от типа, уже есть в clang trunk. Смотрите в прямом эфире на godbolt:

template<typename T>
struct Range
{
    T min, max;
};

template<typename T, Range<T> R>
struct SomeColorSpace
{
    static constexpr Range<T> r = R;

    T component1, component2;
};

using Rgb = SomeColorSpace<float, Range<float>{0.0f, 1.0f}>;

auto test()
{
    Rgb color{0.4f, 0.1f};

    float c1 = color.component1;
    float min = Rgb::r.min;

    return Rgb::r.max;
}

Так что он скоро прибудет в clang. До тех пор возможным обходным путем является использование трейтов. Смотрите в прямом эфире на godbolt:

template<class T, class Trait>
struct SomeColorSpace
{
    static constexpr T min = Trait::min;
    static constexpr T max = Trait::max;

    T component1, component2;
};

struct RgbTrait
{
    static constexpr float min = 0.0f;
    static constexpr float max = 1.0f;
};

using Rgb = SomeColorSpace<float, RgbTrait>;

auto test()
{
    Rgb color{0.4f, 0.1f};

    float c1 = color.component1;
    float min = Rgb::min;

    return Rgb::max;
}

Не совсем понятно, что вы хотите, что касается цвета, r/g/b/(a) будет иметь одинаковый диапазон в зависимости от типа.

Таким образом, простые черты позволяют отображать минимум/максимум float в [0.f,1.f] и std::uint8_t в [0,255]:

template <typename T> struct RangeTraits;

template <> struct RangeTraits<double>
{
    constexpr double min = 0.;
    constexpr double max = 1.;
};
template <> struct RangeTraits<std::uint8_t>
{
    constexpr std::uint8_t min = 0;
    constexpr std::uint8_t max = 255;
};
// ...

И

template <typename T>
struct SomeColorSpace{
    std::array<T, N> components;// N is compile-time constant

// use RangeTraits<T>::min, RangeTraits<T>::max when needed.
};

Другая интерпретация заключается в том, что ваш параметр шаблона является «просто» значением по умолчанию для инициализации:

template <typename T, T DefaultMin, T DefaultMax>
struct Range{
    T min = DefaultMin;
    T max = DefaultMax;

    // Some constructors initializing min and max...
};

но эти значения по умолчанию следует забыть потом

Итак, вы можете сделать что-то вроде:

std::array<Range<std::int8_t>, 2> components{Range<std::int8_t, 0, 127>, Range<std::int8_t, -10, 10>};

Тогда вы можете сделать:

template <typename T, T...> struct Range;

template <typename T>
struct Range<T>
{
    T min;
    T max;

    Range(T min, T max) : min(min), max(max) {}

    template <T Min, T Max,>
    Range(Range<T, Min, Max>& rhs) : min(rhs.min), max(rhs.max) {}

    Range(Range& rhs) = default;
    // ...
};

template <typename T, T Min, T Max>
struct Range<T, Min, Max>
{
    T min = Min;
    T max = Max;

    Range() = default;
    Range(Range& rhs) = default;

    // Possibly keep constructors of conversion and the one with runtime min/max
    // ...
};

Другие вопросы по теме