【问题标题】:Is this the best way to do a "with" statement in C++?这是在 C++ 中执行“with”语句的最佳方式吗?
【发布时间】:2010-10-29 18:52:24
【问题描述】:

编辑:

所以这个问题被误解到如此荒谬的程度,以至于它不再有意义。我不知道如何,因为我实际上的问题是我的具体实现是否——是的,已知毫无意义,是的,与惯用的 C++ 不太相似——宏已经尽可能好,它是否必须使用 auto,或者是否有合适的解决方法。它不应该引起如此多的关注,当然也不会引起如此严重的误解。要求受访者编辑他们的答案是没有意义的,我不希望任何人因此而失去声誉,而且这里有一些很好的信息可供潜在的未来观众使用,所以我将任意选择一个投票率较低的人答案以平均分配所涉及的声誉。继续前进,这里没什么可看的。


我看到 this question 并决定用 C++ 编写 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,因为它是一个不常见的标识符,它的形式给人一种“通用事物”的印象。如果您有一个更好的标识符或更有用的语法的想法,那么请提出建议。

【问题讨论】:

  • 谢谢...看起来很有趣也很有用。
  • @Robert Harvey:它基本上只是{ [const] auto&amp; o = ...; ... } 的简写,但不那么难看。
  • 您的意思是#define with(value) \ 而不是#define with(value, id) \ ?顺便说一句,Boost.Typeof 怎么样?
  • @KennyTM:是的,从测试中复制错误。谢谢你帮我抓住了。 Boost.Typeof 并不理想,因为它不能与用户定义类型开箱即用,这是 with 最重要的用途之一。
  • @CiscolPPhone:完成了。 ;)

标签: c++ c++11 with-statement


【解决方案1】:

如果你使用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);
    }
}

【讨论】:

  • 我已经想到了。我已经提到了。这不是我真正要问的。
【解决方案2】:

??尝试将 vb 语法转换为 C++

with 表示默认情况下执行以下块中的所有操作,引用我说过要使用的对象,对吗? Executes a series of statements making repeated reference to a single object or structure.

with(a)
 .do
 .domore
 .doitall

那么这个例子如何给你相同的语法?

对我来说,为什么要在多个 de 引用中使用 a 的示例

所以而不是

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

【讨论】:

    【解决方案3】:

    对于 C++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);
    
        }
    }
    

    【讨论】:

    • 谢谢,但我实际上并没有假设 C++0x。可能还不清楚。
    • @Jon: auto 因为自动类型推断是 C++0x。干杯,
    • @Alf P. Steinbach:我一直在寻找非auto 的解决方案,因此,特别是非C++0x。但我放弃了。
    • @Jon: 只需使用std::vector&lt;int&gt;&amp; 而不是auto&amp;。或者,如果类型说明本身很长,那么还要为该类型添加一个typedef。干杯&hth.,
    • @Jon:我不认为你有任何意义。你正在用一些非常复杂的 Rube Goldberg 结构做一件绝对微不足道的事情。然后你说没人理解你。
    【解决方案4】:

    为什么不直接使用好的 lambda?

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

    简单的事实是,如果你的标识符太长,你不能每次都输入它们,使用引用、函数、指针等来解决这个问题,或者更好地重构名称。像这样的语句(例如 C# 中的 using())具有额外的副作用(在我的示例中是确定性清理)。您在 C++ 中的声明没有显着的实际好处,因为它实际上并没有调用任何额外的行为来反对仅仅写出代码。

    【讨论】:

    • 这种方法的问题在于它使代码更难阅读——你必须向下跳到 lambda 定义的底部才能找到被操作的对象,然后再跳回图找出代码对那个对象做了什么,而不是按顺序读取代码。
    • @Adam Rosenfield:它还有一个优点是 func 可以通过使用 std::function 动态传递。此外,OP的整个不是真正的问题都是荒谬的。您期待一个不荒谬的解决方案吗?
    • @Adam Rosenfield, @DeadMG:天哪,我只是想知道我写的那个明显、故意无用的宏是否写得像它本来可以写的一样好,以及一系列不相关的答案随之而来。我不想删除这个问题,但已经没有意义了。
    猜你喜欢
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 2011-06-09
    • 2019-08-12
    • 1970-01-01
    • 2011-10-21
    相关资源
    最近更新 更多