автоматическая привязка констант к (нулевому) указателю - что это за тип? - PullRequest
7 голосов
/ 09 мая 2019

При просмотре некоторого кода я наткнулся на конструкцию со следующей строкой:

if (const auto& foo = std::get_if<MyType>(&bar)) // note the ampersand!

, где bar - это std::variant<MyType, OtherType>. Проблема в том, что get_if может возвращать нулевой указатель , и я не понимаю, почему оператор работает.

Рассмотрим этот аналог MCVE:

#include <iostream>

struct Foo { int a = 42; };

Foo* f() { return nullptr; }

int main() {
    const auto& foo = f();          // Returns a nullptr that binds to Foo*& - UB?
    //static_assert(std::is_same<decltype(foo), const Foo*&>::value); // -> Fails
    //const Foo*& bar = f(); // -> Fails

    if (foo)    std::cout << foo->a << std::endl;
    else        std::cout << "nullpointer" << std::endl;
}

Первая строка main() работает нормально, и я ожидаю, что тип bar будет const Foo*&, но статическое утверждение не выполняется. Неудивительно, что следующая строка также не компилируется с cannot bind non-const lvalue reference of type 'const Foo*&' to an rvalue of type 'const Foo*'.

Что происходит в первом утверждении main? Это UB или стандарт содержит какой-то скрытый секрет, который позволяет это быть законным? Какой тип bar?

1 Ответ

10 голосов
/ 09 мая 2019

Обратите внимание, что для const auto& foo, const квалифицируется для части auto, то есть указатель, но не указатель.Тогда тип foo будет Foo* const &, который является ссылкой на const (указатель на не-const Foo), но не const Foo* &, который является ссылка на не-const (указатель на const Foo).

И lvalue-ссылка на const может связываться с rvalue, возвращаемым f(), поэтому const auto& foo = f(); работает нормально;const Foo*& bar = f(); не будет работать, потому что bar - это lvalue-ссылка на не- const;который не может связываться с rvalue.Изменение типа bar на const Foo * const & или Foo* const & (аналогично foo) приведет к его работе.

...