Rvalue-ness типа & amp; & amp; переменные в C ++ [дубликат]

Решение P-A частично работает для меня. Подробно мои выводы ниже:

1) Первый фрагмент кода неверен, см. Ниже:

<activity
    ...
    <intent-filter>
        ==> <action android:name="android.intent.action.MAIN" /> <== This line shouldn't be deleted, otherwise will have compile error
        <category android:name="android.intent.category.LAUNCHER" /> //DELETE THIS LINE
    </intent-filter>
</activity>

2) Должен использовать следующий код для отключения всех значков до включения другого, иначе он добавит новый значок вместо его замены.

getPackageManager().setComponentEnabledSetting(
        getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

НО, если вы используете код выше, то ярлык на главном экране будет удален! И он не будет автоматически добавлен обратно. Возможно, вы сможете программно добавить значок обратно, но он, вероятно, не останется в том же положении, что и раньше.

3) Обратите внимание, что значок не будет изменен немедленно, это может занять несколько секунд. Если вы нажмете его сразу после изменения, вы можете получить сообщение об ошибке: «Приложение не установлено».

Итак, IMHO это решение подходит только для изменения значка только в приложении запуска, а не для быстрого доступа ( т.е. значок на рабочем столе)

4
задан ElefEnt 17 September 2015 в 00:20
поделиться

3 ответа

Когда вы ссылаетесь на переменную по имени, вы всегда получаете lvalue. Исключений из этого правила нет, хотя обратите внимание, что это не относится к препроцессорным макросам, счетчикам или параметрам шаблона непигового типа, ни одна из которых не является переменными в обычном смысле.

Я утверждаю, что хотя это поведение сначала кажется не имеющим смысла, когда вы считаете его более осторожным, оно имеет смысл и является правильным поведением. Во-первых, следует заметить, что категория значений явно является свойством выражений , , а не самих объектов. Это очевидно, так как std::move никогда не создает новый объект, а просто создает выражение rvalue, относящееся к данному объекту. Тогда мы должны понимать, что:

  • Если выражение является lvalue, оно обычно означает, что значение объекта, на которое ссылается выражение, может или будет доступно через одно и то же выражение позже в той же области , Это предположение по умолчанию, когда к объекту обращаются через именованную переменную.
  • Если выражение представляет собой rvalue, это обычно означает, что значение объекта, на которое ссылается выражение, не может или не будет доступно через то же выражение позже в той же области. (Это включает в себя временные значения prvalue, T{} в одном выражении отличается от T{} в более позднем выражении, оба создают анонимные объекты, но оба они различны, поэтому последний не имеет доступа к тому же объекту, что и первый.)

Таким образом, категория значений выражения, ссылающегося на объект, является relative; зависит от конкретного выражения и области видимости. std::move сигнализирует о своем намерении не получать доступ к значению объекта снова в той же области действия, что позволяет вызываемой функции перемещать свое значение из этого объекта. Однако, когда вызываемая функция обращается к имени ссылки rvalue, это значение является постоянным во время вызова функции; функция может перемещать значение из этого объекта в любой точке или вообще не работать, но, во всяком случае, он, вероятно, получит доступ к нему в теле, который после инициализации параметров.

В этом примере :

void f(Foo&& foo) { /* use foo */ }
void g() {
    Foo foo;
    f(std::move(foo));
}

, хотя std::move(foo) в g и параметр foo в вызываемой ссылке относятся к одному и тому же объекту, это значение объекта исчезнет на точки std::move в g, тогда как в f ожидается, что значение этого объекта будет доступно через foo, возможно, несколько раз до конца f.

A аналогичная ситуация существует при вызове ref-квалифицированных функций-членов.

struct Foo {
    void f() &;
    void f() &&;
    void g() && {
        f(); // calls lvalue-qualified f
    }
};
void h() {
    Foo().g();
}

Здесь значение Foo() вот-вот исчезнет из h(); он не будет доступен после полного выражения . Однако в теле Foo::g() он остается постоянным до конца g(); *this надежно обращается к значению одного и того же объекта. Поэтому естественно, что когда g() вызывает f(), он должен вызывать перегрузку, ожидающую lvalue, и f() не должен красть значение *this* из g(), так как g() может все еще хотеть получить к нему доступ .

4
ответ дан Brian 15 August 2018 в 18:00
поделиться

В g() t - именованная переменная. Все именованные переменные являются lvalues. Если T является типом шаблона, вы можете перенаправить переменную на f() с помощью std::forward . Это вызовет f() с тем же типом, который был передан в g()

template<typename T>
g(T&& t) { f(std::forward<T>(t));}

Если T не тип шаблона, а просто тип, вы можете использовать std::move

g(T&& t) { f(std:move(t)); }
3
ответ дан NathanOliver 15 August 2018 в 18:00
поделиться
  • 1
    Извините, но я не понял. Что такое & quot; не тип шаблона & quot ;? С OR без шаблонов, мой код ideone.com/NL0EDv , похоже, не имеет проблем с использованием std::move, то зачем вообще использовать forward? – Saurav Sahu 22 August 2017 в 15:41

То, что автоматически обрабатывается как rvalues, это вещи без имен, а вещи, которые (очень скоро) не будут иметь имени (в случае возвращаемого значения).

T&& t имеет имя, это t.

Причина, по которой rvalues ​​- это то, что ссылается на них после , что точка использования почти невозможна.

T&& является ссылкой типа rvalue. Ссылка rvalue может связываться только с rvalue (без участия static_cast), но в остальном это значение lvalue типа rvalue.

Тот факт, что он относится к типу rvalue, имеет значение только во время его построения , и если вы сделаете decltype(variable_name). В противном случае это просто другое значение ссылочного типа.

std::move(t) выполняет return static_cast<T&&>(t); и возвращает ссылку rvalue.

Правила, которые регулируют это, написаны стандартными в стандарте C ++. Копия / вставка из них не все так полезно, потому что их не так просто понять.

Первое общее правило: вы получаете неявный ход (aka, параметр, который привязывается к rvalue ссылочный аргумент), когда вы возвращаете именованное значение из функции или когда значение не имеет имени или когда функция явно возвращает ссылку rvalue.

Во-вторых, только ссылки rvalue и const& могут связываться на rvalues.

В-третьих, расширение жизненного цикла ссылки на временные значения происходит, когда напрямую связано с ссылкой вне конструктора. (поскольку только ссылки rvalue и const& могут напрямую привязываться к временному, это относится только к ним)

Forth, T&& не всегда является ссылкой rvalue. Если T имеет тип X& или X const&, тогда свертывание ссылки сворачивает T&& в X& или X const&.

Наконец, T&& в контексте вывода типа выводит T в качестве X, X&, X const& или X const&& в зависимости от типа аргумента и, следовательно, может выступать в качестве «ссылки пересылки».

9
ответ дан Yakk - Adam Nevraumont 15 August 2018 в 18:00
поделиться
  • 1
    Что вы подразумеваете под & quot; Ссылка rvalue может привязываться только к rvalue без static_cast & quot ;? – ElefEnt 17 September 2015 в 02:26
  • 2
    @ElefEnt связывается во время строительства – Yakk - Adam Nevraumont 17 September 2015 в 04:03
Другие вопросы по тегам:

Похожие вопросы: