Из-за чего requires!std::is_void_v работает только для шаблона?

Ссылка скопирована
1 ответ
T& GetValue() const requires !std::is_void_v<T> //C7683 { return *_value; } template<typename TValue = T> requires !std::is_void_v<TValue> TValue& GetValueAs() const { return static_cast<TValue&>(*_value); }
Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Редакция DevOps Ответ

Проблема в том, что requires у обычного метода класса зависит от параметров шаблона класса, а не от параметров самого метода. Если T - параметр шаблона класса, то выражение requires !std::is_void_v<T> должно быть корректно в контексте инстанцирования класса. В некоторых компиляторах/режимах Visual C++ можно получить C7683, если constrained non-template member пытается использовать условие так, как будто оно SFINAE-отключает метод.

Шаблонный метод GetValueAs работает, потому что TValue - параметр шаблона самого метода. Constraint применяется к конкретной подстановке метода, и компилятору проще исключить его из overload set.

Один из рабочих вариантов - сделать GetValue тоже шаблонным с параметром по умолчанию:

template&lt;typename TValue = T&gt;
TValue&amp; GetValue() const
    requires (!std::is_void_v&lt;TValue&gt;)
{
    return static_cast&lt;TValue&amp;&gt;(*_value);
}

template&lt;typename TValue = T&gt; TValue&amp; GetValue() const requires (!std::is_void_v&lt;TValue&gt;) { return static_cast&lt;TValue&amp;&gt;(*_value); }

Если возвращать нужно именно T&, можно так:

template&lt;typename TValue = T&gt;
T&amp; GetValue() const
    requires (!std::is_void_v&lt;TValue&gt;)
{
    return *_value;
}

template&lt;typename TValue = T&gt; T&amp; GetValue() const requires (!std::is_void_v&lt;TValue&gt;) { return *_value; }

Но если T может быть void, поле _value тоже должно быть устроено так, чтобы для void оно не требовало T& или разыменования. Иначе метод вы отключите, но класс все равно может быть некорректен из-за хранения void.

Еще вариант - специализировать класс для void или вынести value-хранилище в helper, который по-разному устроен для void и не-void.

Вывод: ваш второй вариант работает не случайно, а потому что constraint привязан к шаблонному параметру метода. Для максимальной совместимости с MSVC сделайте GetValue шаблонным или разделите специализации класса. Это нормальная практика для API, где T может быть void.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно