Это лучший способ сделать оператор with в С++?

Изменить:

Таким образом, этот вопрос был неправильно истолкован до такой смехотворной степени, что он больше не имеет смысла. Я не знаю, как, поскольку вопрос, который я на самом деле задал, заключался в том, моя конкретная реализация этого да, известная как бессмысленная, да, не напоминающий идиоматический макрос C++, был настолько хорош, насколько мог быть, и обязательно ли он должен был использовать auto, или вместо этого существовало подходящее обходное решение. Это не должно было вызвать такого большого внимания и уж точно не такого масштаба непонимания. Бессмысленно просить респондентов редактировать свои ответы, я не хочу, чтобы кто-то терял репутацию из-за этого, и здесь есть некоторая полезная информация для потенциальных будущих зрителей, поэтому я собираюсь произвольно выбрать один из тех, кто получил меньше голосов. ответы для равномерного распределения вовлеченной репутации. Проходи мимо, здесь не на что смотреть.


Я увидел этот вопрос и решил, что было бы интересно написать оператор with в С++. Ключевое слово auto делает это действительно простым, но есть ли лучший способ сделать это, возможно, без использования auto? Я опустил некоторые части кода для краткости.

template<class T>
struct with_helper {

    with_helper(T& v) : value(v), alive(true) {}

    T* operator->() { return &value; }
    T& operator*() { return value; }

    T& value;
    bool alive;

};


template<class T> struct with_helper<const T> { ... };


template<class T> with_helper<T>       make_with_helper(T& value) { ... }
template<class T> with_helper<const T> make_with_helper(const T& value) { ... }


#define with(value) \
for (auto o = make_with_helper(value); o.alive; o.alive = false)

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

int main(int argc, char** argv) {

    Object object;

    with (object) {

        o->member = 0;
        o->method(1);
        o->method(2);
        o->method(3);

    }

    with (object.get_property("foo").perform_task(1, 2, 3).result()) {

        std::cout
            << (*o)[0] << '\n'
            << (*o)[1] << '\n'
            << (*o)[2] << '\n';

    }

    return 0;

}

Я выбрал o, потому что это необычный идентификатор, а его форма производит впечатление "обычной вещи". Если у вас есть идея для лучшего идентификатора или более удобного синтаксиса в целом, пожалуйста, предложите это.


person Jon Purdy    schedule 29.10.2010    source источник
comment
Спасибо... Выглядит интересно и полезно.   -  person Robert Harvey    schedule 29.10.2010
comment
@Robert Harvey: Это просто сокращение от { [const] auto& o = ...; ... }, но немного менее уродливое.   -  person Jon Purdy    schedule 29.10.2010
comment
Вы имеете в виду #define with(value) \ вместо #define with(value, id) \ ? Кстати, как насчет Boost.Typeof?   -  person kennytm    schedule 29.10.2010
comment
@KennyTM: Да, ошибка копирования при тестировании. Спасибо, что поймал это для меня. Boost.Typeof не идеален, потому что он не работает сразу с пользовательскими типами, что является одним из наиболее важных применений with.   -  person Jon Purdy    schedule 29.10.2010
comment
Какая польза от этого? Разве это не просто добавляет больше строк кода и дополнительных блоков кода?   -  person Inverse    schedule 29.10.2010
comment
@Inverse: Ха. я точно не знаю! Людям, похоже, нравятся их with утверждения, когда они у них есть. Я никогда не говорил, что считаю его особенно полезным как таковым. Это всего лишь мимолетная мысль, но я должен задаться вопросом, есть ли возможности для улучшения.   -  person Jon Purdy    schedule 29.10.2010
comment
если бы у вас были очень длинные имена переменных для ваших векторов, люди могли бы увидеть использование: P   -  person CiscoIPPhone    schedule 29.10.2010
comment
@CiscolPPhone: Сделано и сделано. ;)   -  person Jon Purdy    schedule 29.10.2010
comment
@dalle: ... есть ли лучший способ сделать это, возможно, без использования auto?   -  person Jon Purdy    schedule 30.10.2010
comment
@Purdy Вас может заинтересовать это предложение по обмену стеками . Он почти готов к началу бета-тестирования, просто нужно еще несколько.   -  person greatwolf    schedule 18.01.2011


Ответы (4)


?? попытка синтаксиса vb в C++

with говорит делать все, что в следующем блоке, по умолчанию, ссылаясь на объект, с которым я сказал, правильно? Выполняет ряд инструкций, повторяющих ссылки на один объект или структура.

with(a)
 .do
 .domore
 .doitall

так как пример дает вам тот же синтаксис?

мне примеры того, почему использовать с где несколько ссылок

так, а не

book.sheet.table.col(a).row(2).setColour
book.sheet.table.col(a).row(2).setFont
book.sheet.table.col(a).row(2).setText
book.sheet.table.col(a).row(2).setBorder

у вас есть

with( book.sheet.table.col(a).row(2) )
  .setColour
  .setFont
  .setText
  .setBorder

кажется таким же простым и более распространенным синтаксисом в C++ для

cell& c = book.sheet.table.col(a).row(2);
c.setColour
c.setFont
c.setText
c.setBorder
person Greg Domjan    schedule 29.10.2010

Если вы используете auto, зачем вообще использовать макросы?

int main()
{
    std::vector<int> vector_with_uncommonly_long_identifier;

    {
        auto& o = vector_with_uncommonly_long_identifier;

        o.push_back(1);
        o.push_back(2);
        o.push_back(3);
    }

    const std::vector<int> constant_duplicate_of_vector_with_uncommonly_long_identifier
        (vector_with_uncommonly_long_identifier);

    {
        const auto& o = constant_duplicate_of_vector_with_uncommonly_long_identifier;

        std::cout
            << o[0] << '\n'
            << o[1] << '\n'
            << o[2] << '\n';
    }

    {
        auto o = constant_duplicate_of_vector_with_uncommonly_long_identifier.size();
        std::cout << o <<'\n';
    }
}

РЕДАКТИРОВАТЬ: без auto просто используйте typedef и ссылки.

int main()
{
    typedef std::vector<int> Vec;

    Vec vector_with_uncommonly_long_identifier;

    {
        Vec& o = vector_with_uncommonly_long_identifier;

        o.push_back(1);
        o.push_back(2);
        o.push_back(3);
    }
}
person dalle    schedule 29.10.2010
comment
Я уже думал об этом. Я уже упомянул это. Это не совсем то, о чем я спрашивал. - person Jon Purdy; 30.10.2010

Для С++ 0x (что вы предполагаете):

int main() {

    std::vector<int> vector_with_uncommonly_long_identifier;

    {
        auto& o = vector_with_uncommonly_long_identifier;

        o.push_back(1);
        o.push_back(2);
        o.push_back(3);

    }
}
person Cheers and hth. - Alf    schedule 29.10.2010
comment
Спасибо, но на самом деле я не предполагал C++0x. Может быть, это не ясно. - person Jon Purdy; 30.10.2010
comment
@Jon: auto, так как автоматическое определение типа — это C++0x. Ваше здоровье, - person Cheers and hth. - Alf; 30.10.2010
comment
@Alf P. Steinbach: я искал решение, отличное от auto, следовательно, конкретно не C++0x. Но я сдался. - person Jon Purdy; 30.10.2010
comment
@Jon: просто сделай std::vector<int>& вместо auto&. Или, если сама спецификация типа длинная, добавьте typedef для типа. Ура и чт., - person Cheers and hth. - Alf; 30.10.2010
comment
@Jon: Я не думаю, что ты прав. Вы делаете абсолютно тривиальную вещь с довольно сложной конструкцией Руба Голдберга. Тогда вы говорите, что вас никто не понимает. - person Cheers and hth. - Alf; 03.11.2010
comment
@Alf: Я думаю, что это немного экстремально, но опять же, не беспокойтесь об этом. - person Jon Purdy; 03.11.2010

Почему бы просто не использовать хорошую лямбду?

auto func = [&](std::vector<int>& o) {
};
func(vector_with_a_truly_ridiculously_long_identifier);

Простой факт заключается в том, что если ваши идентификаторы настолько длинные, что вы не можете вводить их каждый раз, используйте ссылку, функцию, указатель и т. д., чтобы решить эту проблему, или, что еще лучше, рефакторинг имени. Подобные операторы (например, using() в C#) имеют дополнительные побочные эффекты (в моем примере детерминированная очистка). Ваше утверждение на С++ не имеет заметных реальных преимуществ, поскольку оно фактически не вызывает никакого дополнительного поведения вместо простого написания кода.

person Puppy    schedule 29.10.2010
comment
Проблема с этим подходом заключается в том, что он затрудняет чтение кода — вам нужно прыгнуть вниз к нижней части лямбда-определения, чтобы найти объект, над которым выполняется действие, а затем вернуться обратно, чтобы выяснить, что код делает с этим объектом. объект, а не просто читать код по порядку. - person Adam Rosenfield; 30.10.2010
comment
@Adam Rosenfield: Преимущество также в том, что func можно динамически передавать с помощью std::function. Более того, вся проблема ОП в целом смешна. Вы ожидаете не смешного решения? - person Puppy; 30.10.2010
comment
@Adam Rosenfield, @DeadMG: Боже, я просто получаю ошибку, чтобы узнать, был ли написан явно, намеренно бесполезный макрос, который я написал, так, как мог бы быть, и следует множество не относящихся к делу ответов. Я не хочу удалять вопрос, но в нем больше нет смысла. - person Jon Purdy; 30.10.2010