C++ const_cast использование вместо бросков C-стиля

Нашел решение, которое, похоже, и используется Google для запуска Android TV.

Вкратце: создайте пользовательский VerticalGridView и переопределите его метод focusSearch(), чтобы определить, как перемещать / менять элементы.

Что-то похожее на это:

class EditableVerticalGridView @JvmOverloads constructor(context: Context,
                                                         attrs: AttributeSet? = null,
                                                         defStyle: Int = 0) :
        VerticalGridView(context, attrs, defStyle) {

    override fun focusSearch(focused: View, direction: Int): View {
        return if (focused.isSelected) {
            swapItemsIfNeeded(focused, direction)
        } else super.focusSearch(focused, direction)
    }

    private fun swapItemsIfNeeded(focused: View, direction: Int): View {
        val position = getChildAdapterPosition(focused)
        if (!itemAnimator.isRunning) {
            if (canMoveInDirection(position, direction)) {
                when (direction) {
                    FOCUS_LEFT -> moveChannel(position, position - 1)
                    FOCUS_UP -> moveChannel(position, position - NUM_COLUMN)
                    FOCUS_RIGHT -> moveChannel(position, position + 1)
                    FOCUS_DOWN -> moveChannel(position, position + NUM_COLUMN)
                }
            }
        }
        return focused
    }

    private fun canMoveInDirection(position: Int, direction: Int): Boolean {
        when (direction) {
            FOCUS_LEFT -> {
                return position % NUM_COLUMN > 0
            }
            FOCUS_UP -> {
                return position - NUM_COLUMN >= 0
            }
            FOCUS_RIGHT -> {
                return !(position % NUM_COLUMN >= (NUM_COLUMN - 1) ||
                        position >= adapter.itemCount - 1)
            }
            FOCUS_DOWN -> {
                return position + NUM_COLUMN <= adapter.itemCount - 1
            }
            else -> {
                return false
            }
        }
    }

    private fun moveChannel(fromPosition: Int, toPosition: Int) {
        (adapter as AllowedChannelAdapter).moveChannel(fromPosition, toPosition)
    }

    companion object {

        private const val NUM_COLUMN: Int = 6

    }

}

... и функция moveChannel():

fun moveChannel(from: Int, to: Int) {
        var offset = 1
        if (from >= 0 && from <= channelItems.size - 1 && to >= 0 && to <= channelItems.size - 1) {
            val fromItem = channelItems[from]
            channelItems[from] = channelItems[to]
            channelItems[to] = fromItem
            notifyItemMoved(from, to)

            val positionDifference = to - from
            if (Math.abs(positionDifference) > 1) {
                if (positionDifference > 0) {
                    offset = -1
                }
                notifyItemMoved(to + offset, from)
            }
        }
    }
7
задан JaredPar 16 December 2008 в 06:47
поделиться

3 ответа

  const int i0 = 5;
//int       i1 = const_cast<int>(i0);       // compilation error
  int       i2 = (int)i0;                   // okay

  int       i3 = 5;
//const int i4 = const_cast<const int>(i3); // compilation error
  const int i5 = (const int)i3;             // okay

Ошибки компиляции вызываются, потому что Вы не бросаете константу далеко/добавлять константа. Вместо этого Вы копируете i0. Для той операции никакой бросок не требуется вообще:

int i1 = i0;
const int i4 = i3;

Тип, к которому Вы бросаете, должен на самом деле быть указателем или ссылкой. Иначе использование const_cast не имеет смысла, так как Вы могли прямо скопировать его. Для указателей, например, можно выбросить константу, потому что разыменование указателя приведет к другому типу для a const T* (урожаи const T) чем для a T* (урожаи T). Для ссылок то же верно: T& получит доступ к объекту с помощью другого этого типа указателя, чем использование const T&. Теперь, что Вы действительно хотели заархивировать:

  const int i0 = 5;
//int &     i1 = const_cast<int&>(i0);      // okay (but dangerous)
  int &     i2 = (int&)i0;                  // okay (but dangerous)

  int       i3 = 5;
//const int&i4 = const_cast<const int&>(i3); // ok now and valid!
  const int&i5 = (const int&)i3;             // okay too!

Вышеупомянутое может привести к неопределенному поведению, когда Вы пишете в первоначально объект константы через ссылку на неконстанту (на самом деле, просто бросание и читать его не являются неопределенным поведением сам по себе. Но если Вы выбрасываете константу, можно также записать в нее, который затем приводит к неопределенному поведению),

20
ответ дан 6 December 2019 в 07:08
поделиться

Это - ошибка, потому что в стандарте говорится, что это не позволяется. Стандарт перечисляет виды преобразований это const_cast позволяется сделать, и это запрещает что-либо не в списке. Это позволяет следующее:

  • Указатели
  • Ссылки
  • Членские указатели

Так как Ваши типы не являются ни одним из тех, им не позволяют.

С другой стороны для примеров, которые Вы дали, не нужно const_cast, также.

5
ответ дан 6 December 2019 в 07:08
поделиться

Для первой ошибки. const_cast может только использоваться на типах указателей или ссылочных типах. "интервал" не ни один. Это может или не может быть стандартом C++ (не мог найти хорошую ссылку). Но это имеет место для определенных реализаций, таких как компилятор C++ MS.

Для второй ошибки. const_cast может только использоваться для удаления константы, или энергозависимый спецификатор не добавляют его.

Ссылка: http://msdn.microsoft.com/en-us/library/bz6at95h (по сравнению с 80) .aspx

0
ответ дан 6 December 2019 в 07:08
поделиться
Другие вопросы по тегам:

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