Можно ли создать шаблонный гид для вывода типов, учитывающий только второй аргумент?

Можно ли задать первый аргумент явно для класса `Lazy`, чтобы использовать его в следующем примере: 

```cpp
Lazy<Cursor> Arrow = [] { return Cursor(SDL_SYSTEM_CURSOR_ARROW); };
```

при этом сохранив возможность использовать шаблонный параметр `TFactory`, как показано в следующем коде: 

```cpp
template <typename T, typename TFactory = DefaultValueFactory<T>>
class Lazy final { /*...*/};
``` 

Ведут ли изменения к улучшению читаемости и контролю параметров шаблона в данном случае?
  • 5 апреля 2025 г. 6:04
Ответы на вопрос 2
Да, вы можете создать шаблонный класс `Lazy`, который будет иметь первый аргумент явно заданным, а второй аргумент — параметром шаблона с умолчанием. Это позволит вам задать необходимую функциональность, связанную с `TFactory`, при этом сохранив возможность явно указывать тип для `Lazy`.

Ваш класс можно реализовать следующим образом:

```cpp
template <typename TFactory = DefaultValueFactory<Cursor>>
class Lazy final {
public:
    using ResultType = Cursor;

    Lazy(std::function<ResultType()> factory)
        : factory_(factory) {}

    ResultType get() {
        if (!isInitialized_) {
            value_ = factory_();
            isInitialized_ = true;
        }
        return value_;
    }

private:
    std::function<ResultType()> factory_;
    ResultType value_;
    bool isInitialized_ = false;
};
```

Теперь, когда вы создаете экземпляр `Lazy` с типом `Cursor`, вы можете указать только второй аргумент, например:

```cpp
Lazy<> Arrow = [] { return Cursor(SDL_SYSTEM_CURSOR_ARROW); };
```

Или, если вам нужно явно указать фабрику:

```cpp
Lazy<MyCustomFactory> Arrow = [] { return Cursor(SDL_SYSTEM_CURSOR_ARROW); };
```

Что касается читаемости и контроля параметров шаблона, такой подход подойдет, если:

1. Вы всегда используете один и тот же тип для первого аргумента, что упрощает использование класса и предотвращает возможные ошибки с типами.
2. Вы хотите сохранить возможность использовать разные фабрики, если у вас есть инструменты для создания объектов и вам нужно это разнообразие.

Благодаря этому конструкция становится более понятной, поскольку вы явно разделяете параметры шаблона на два, и это может улучшить понимание кода другими программистами, особенно если они знают, что `T` будет всегда типом `Cursor`. Однако, как и везде, всё зависит от контекста использования и предпочтений команды разработчиков, поэтому важно учитывать конкретные требования вашего проекта.
Пока получилось через функцию. <br/> <br/> <pre><code class="cpp">#include &lt;utility&gt;
#include &lt;iostream&gt;

class Cursor {
public:
    Cursor(int aShape) noexcept : fShape(aShape) {}
    int shape() const noexcept { return fShape; }
private:
    int fShape;
};

template &lt;typename T, typename TFactory&gt;
class Lazy {
public:
    Lazy(TFactory&amp;&amp; x) : factory(std::move(x)) {}
    Lazy(const TFactory&amp; x) : factory(x) {}
    T operator()() const { return factory(); }
private:
    mutable TFactory factory;
};

template &lt;typename T, typename TFactory&gt;
inline auto lazy(TFactory&amp;&amp; factory)
{
    return Lazy&lt;T, std::decay_t&lt;TFactory&gt;&gt;(std::forward&lt;TFactory&gt;(factory));
}

int main()
{
    auto arrow = lazy&lt;Cursor&gt;([] { return Cursor(42); } );
    std::cout &lt;&lt; arrow().shape() &lt;&lt; '\n';
    return 0;
}</code></pre> <br/> <br/> Может, шаблонного полиморфизма вам хватит, но я бы довольно быстро прикрутил виртуальный полиморфизм.
Похожие вопросы