Как мне проверить, является ли тип контекстуально конвертируемым в bool?

Я хочу написать концепцию, описывающую объекты-функции, которые не только вызываются , но и, например,std::function, иметь «пустое» состояние , которое можно проверить с помощью контекстного преобразования в .

Булева проверяемая концепция « только экспозиция» звучит так, как будто она может быть уместной, но, поскольку она написана в терминахconvertible_to, требует, чтобы его аргумент был неявно конвертирован в bool:

      template<class T> concept BooleanTestable = std::convertible_to<T, bool>;
static_assert(BooleanTestable<void(*)()>); // ok
static_assert(BooleanTestable<std::function<void()>>); // fails :(

Есть ли что-то в стандарте <concepts>библиотека, которая может помочь, или мне нужно самому написать require-expression, и если да, то какую форму я должен использовать? Определение контекстно преобразованного в boolвыражается в виде декларации-оператора (т.е. bool t(E);), но require-expressions может проверять только выражения:

      template<class T> concept ContextuallyConvertibleToBool = requires (T x) {
    bool(x); // constructor cast?
    static_cast<bool>(x); // or static_cast?
    x ? void() : void(); // or something a little stranger?
};

Учитывая отнесение к категории, удобочитаемость и обслуживание, я бы предпочел использовать форму, имеющую прецедент.

1 ответ

Формулировкаcontextually convertibleприменимо к выражениям, а не к типам.

Некоторые языковые конструкции требуют, чтобы выражение было преобразовано в логическое значение. Говорят, что выражение E, появляющееся в таком контексте, контекстуально преобразуется в bool и является корректным тогда и только тогда, когда объявление bool t(E); корректно для некоторой выдуманной временной переменной t ([dcl.init]).

Вот почему точное определение концепции зависит от вашего контекста и того, что именно вы хотите ограничить.

Ниже приведен пример типа, который проходитconstructible_from<bool, T>test, но не компилируется:

      struct S {
    constexpr explicit operator bool() && noexcept {
        return false;
    }
};

void F() {
    S s;
    static_assert(std::constructible_from<bool, S>);
    if (s) {

    }
}

То, что мы, вероятно, хотим выше, этоstd::constructible_from<bool, S&>. Но это также влияет на имя вашего концепта, потому что теперь вы проверяете не тот факт, что ваш тип является контекстуально конвертируемым, а может ли ваш тип использоваться в конкретном контексте. Например:

      struct S1 {
    constexpr explicit operator bool() && noexcept {
        return false;
    }
};

struct S2 {
    constexpr explicit operator bool() noexcept {
        return false;
    }
};

template <typename T>
concept CanBeUsedWithF = std::constructible_from<bool, T&>;

template <CanBeUsedWithF T>
void F() {
    T s;
    if (s) {

    }
}

F<S1>();  // constraints not satisfied
F<S2>();
Другие вопросы по тегам