яка корисна скринька для явного (bool)


24

C ++ 20 вводить явний (bool), який умовно вибирає під час компіляції, чи буде конструктор явним чи ні.

Нижче наведено приклад, який я знайшов тут .

struct foo {

  // Specify non-integral types (strings, floats, etc.) require explicit construction.

  template <typename T>

  explicit(!std::is_integral_v<T>) foo(T) {}

};

foo a = 123; // OK

foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit specifier evaluates to true)

foo c {"123"}; // OK

Хто-небудь може сказати мені будь-який інший набір для explicit (bool)використання, крім використання std::is_integral?


1
Один із прикладів - стає набагато простіше реалізовувати умовно явні конструктори, такі як для tupleцієї функції.
Преторіанський

1
Не правильна відповідь, але ви також можете подивитися на мотивацію у статті, яка її запровадила: wg21.link/p0892
N. Shead

Приклад: він (разом з поняттями) скорочує необхідну кількість базових класів для реалізації умовно наданого умовно явного конструктора копій від 3 до 0.
LF

Відповіді:


21

Саму мотивацію можна побачити у статті .

Необхідно зробити конструктори умовно явними. Тобто ви хочете:

pair<string, string> safe() {
    return {"meow", "purr"}; // ok
}

pair<vector<int>, vector<int>> unsafe() {
    return {11, 22}; // error
}

Перше добре, ті конструктори неявні. Але останнє було б погано, такі конструктори є explicit. Для C ++ 17 (або C ++ 20 з поняттями) єдиний спосіб зробити цю роботу - написати два конструктори - один explicitі один не:

template <typename T1, typename T2>
struct pair {
    template <typename U1=T1, typename U2=T2,
        std::enable_if_t<
            std::is_constructible_v<T1, U1> &&
            std::is_constructible_v<T2, U2> &&
            std::is_convertible_v<U1, T1> &&
            std::is_convertible_v<U2, T2>
        , int> = 0>
    constexpr pair(U1&&, U2&& );

    template <typename U1=T1, typename U2=T2,
        std::enable_if_t<
            std::is_constructible_v<T1, U1> &&
            std::is_constructible_v<T2, U2> &&
            !(std::is_convertible_v<U1, T1> &&
              std::is_convertible_v<U2, T2>)
        , int> = 0>
    explicit constexpr pair(U1&&, U2&& );    
};  

Вони майже повністю дублюються - і визначення цих конструкторів були б ідентичними.

З explicit(bool), ви можете просто написати один конструктор - із умовно явною частиною конструкції, локалізованою лише на explicit-специфікаторі:

template <typename T1, typename T2>
struct pair {
    template <typename U1=T1, typename U2=T2,
        std::enable_if_t<
            std::is_constructible_v<T1, U1> &&
            std::is_constructible_v<T2, U2>
        , int> = 0>
    explicit(!std::is_convertible_v<U1, T1> ||
        !std::is_convertible_v<U2, T2>)
    constexpr pair(U1&&, U2&& );   
};

Це краще відповідає намірам, набагато менше коду для запису і менше роботи компілятору для виконання під час вирішення перевантаження (оскільки менше конструкторів потрібно вибирати між).


1
C ++ 20 також забезпечує можливість зміни enable_if_tдеталі на красивіше і простіше обмеження, можливо, використовуючи поняття. Але це поруч із суть цього питання.
aschepler

2

Ще одне можливе використання, яке я бачу, - з варіативним шаблоном:

Зазвичай за замовчуванням добре мати explicitдля конструктора лише один аргумент (якщо не потрібна конверсія).

тому

struct Foo
{
    template <typename ... Ts>
    explicit(sizeof...(Ts) == 1) Foo(Ts&&...);

    // ...
};

0

Я міг побачити випадок використання для того, щоб explicitумовно вимагати, коли вхід може бути типу схожого на перегляд (необроблений покажчик std::string_view), на який буде утримуватися новий об’єкт після виклику (лише копіювання представлення даних, а не те, на що він посилається, залишається залежною від термін експлуатації переглянутого об'єкта), або він може бути типом, подібним до значення (приймає право на копію, без зовнішніх залежностей від життя).

У такій ситуації, що викликає, абонент відповідає за збереження переглянутого об'єкта живим (викликає власник подання, а не оригінальний об'єкт), і перетворення не повинно здійснюватися неявно, оскільки це робить занадто легким для імпліцитно створеного об'єкта пережив предмет, який він переглядає. Навпаки, для типів значень новий об’єкт отримає власну копію, тому, хоча копія може бути дорогою, вона не зробить код помилковим, якщо відбудеться неявна конверсія.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.