Избежание постоянного / неконстантного дублирования метода, принимающего лямбду - PullRequest
0 голосов
/ 05 мая 2018

class Frame<P> представляет изображение с пикселями типа P. Алгоритм, который повторяет свои пиксели, нетривиален из-за нескольких гибких возможностей в базовом формате буфера данных.

template <typename P, bool RM = true> // P is pixel type; RM = is_row_major
class Frame {

    // ...

    template<typename F>
    void iterate(F f) { // iterate in a way that is performant for this buffer
        if (stride == (RM ? size.w : size.h)) {
            auto n = size.area();
            for (index_t k = 0; k < n; k++) {
                f(view[k]);
            }
        }
        else {
            auto s = static_cast<index_t>(stride)*(RM ? size.h : size.w);
            for (index_t k0 = 0; k0 < s; k0 += stride) {
                auto m = k0 + (RM ? size.w : size.h);
                for (index_t k = k0; k < m; k++) {
                    f(view[k]);
                }
            }
        }
    }
}

Я хотел бы иметь возможность звонить как iterate(fc) const, так и iterate(f) (с лямбда-сигнатурами fc(const P&) и f(P&) соответственно). Я мог бы продублировать все тело функции и прикрепить const к подписи, но есть ли лучший способ?

1 Ответ

0 голосов
/ 05 мая 2018

Невозможно определить const функций-членов. Однако использование ссылок пересылки позволяет определить cost аргументы функции. Таким образом, вы можете просто делегировать функции, принимая тип объекта в качестве аргумента и передавая все остальные аргументы. Таким образом, дублированный код становится тривиальным. Если функции нужен доступ к private или protected членам, вы просто сделаете ее (вероятно, private) static членом:

template <typename T, bool PM = true>
class Frame {
    template <typename F1, typename F2>
    static void iterateTogether(F1&& f1, F2&& f2) {
        // actual implementation goes here
    }
public:
    template <typename F2>
    void iterateTogether(F2&& other){
        iterateTogether(*this, std::forward<F2>(other));
    }
    // ...
 };

Реализация, использованная выше, также позволяет различать const ness параметра. Если вы хотите ограничить параметр на самом деле просто специализацией Frame, вам нужно ограничить функцию, которая, однако, легко выполняется.

Мое личное предпочтение - иметь в любом случае только тривиальные члены и делегировать все нетривиальные универсальным алгоритмам. Я предпочитаю, чтобы классы просто сохраняли свои инварианты, а интересные применения реализованы с помощью алгоритмов.

...