循环遍历chrono中的所有月份。

huangapple go评论78阅读模式
英文:

Loop over all months in chrono

问题

需要在代码中迭代所有月份:

```C++
for (auto m = std::chrono::January; m <= std::chrono::December; m++)
  std::cout << std::format(std::locale{ "pt_BR.UTF-8" }, "{:L%B}\n", m);

但是出现了无限循环,因为std::chrono::month的增量行为是模12 + 1。因此,当循环中的变量m达到December(12)时,它会回绕到January(1)。

我尝试使用std::views::iota

for (auto m : std::views::iota(std::chrono::January) | std::views::take(12))
  std::cout << std::format(std::locale{ "pt_BR.UTF-8" }, "{:L%B}\n", m);

但是无法编译,因为std::chrono::month不满足std::weakly_incrementable概念。


<details>
<summary>英文:</summary>

I need iterate all months in a code:

```C++
for (auto m = std::chrono::January; m &lt;= std::chrono::December; m++)
  std::cout &lt;&lt; std::format(std::locale { &quot;pt_BR.UTF-8&quot; }, &quot;{:L%B}\n&quot;, m);

But it happens it's a infinity loop, because the std::chrono::month increment has a modulo 12 + 1 behavior. So when the loop m variable reaches December (12), it wraps around to January (1).

I tried with std::views::iota:

for (auto m : std::views::iota(std::chrono::January) | std::views::take(12))
  std::cout &lt;&lt; std::format(std::locale { &quot;pt_BR.UTF-8&quot; }, &quot;{:L%B}\n&quot;, m);

But fails to compile as std::chrono::month don't satisfies the concept std::weakly_incrementable.

答案1

得分: 8

你可以使用一个无符号循环!

for (unsigned i = 1; i <= 12; i++)
  std::cout << std::format(std::locale { "pt_BR.UTF-8" }, "{:L%B}\n", 
                           std::chrono::month { i });

如果你想要更高级一些,你可以为 std::chrono::month 定义 std::incrementable_traits 以与 std::views::iota 一起使用:

namespace std {
  template <>
  struct incrementable_traits<std::chrono::month> 
    : incrementable_traits<unsigned> {};
}

for (auto m : std::views::iota(std::chrono::January) | std::views::take(12))
  std::cout << std::format(std::locale { "pt_BR.UTF-8" }, "{:L%B}\n", m);

请注意,我只翻译了代码部分,不包括注释或其他内容。

英文:

Your can use a unsigned loop!

for (unsigned i = 1; i &lt;= 12; i++)
  std::cout &lt;&lt; std::format(std::locale { &quot;pt_BR.UTF-8&quot; }, &quot;{:L%B}\n&quot;, 
                           std::chrono::month { i });

If you get fancy you can define std::incrementable_traits for std::chrono::month to work with std::views::iota:

namespace std {
  template &lt;&gt;
  struct incrementable_traits&lt;std::chrono::month&gt; 
    : incrementable_traits&lt;unsigned&gt; {};
}

for (auto m : std::views::iota(std::chrono::January) | std::views::take(12))
  std::cout &lt;&lt; std::format(std::locale { &quot;pt_BR.UTF-8&quot; }, &quot;{:L%B}\n&quot;, m);

答案2

得分: 1

你可以使用一个for-range循环。

我已经取消模板化我的from_to(包括)以便更容易看到逻辑。类似于Boost的irange

(我还有from_til(正常半开区间),after_to(不常见的半开区间),和after_til(不常见的介于区间之间)。

#include <chrono>
#include <iostream>
#include <stdexcept>

namespace {

struct from_to {
    bool done{ false };
    std::chrono::month hot;
    std::chrono::month last;
    from_to(std::chrono::month first, std::chrono::month last_) : hot{first}, last{last_} {}
    auto operator*() const -> std::chrono::month { return hot; }
    bool operator!=(from_to const&) const { return not done; }
    void operator++() {
        if (done) throw std::logic_error("increment past end");
        if (hot == last) done = true;
        else ++hot;
    }
    auto begin() const -> from_to const& { return *this; }
    auto end() const -> from_to const& { return *this; }
};

auto to_cstr(std::chrono::month m) -> char const* {
    switch (m.operator unsigned()) {
#define CASE(x) case std::chrono::x.operator unsigned(): return #x
        CASE(January);
        CASE(February);
        CASE(March);
        CASE(April);
        CASE(May);
        CASE(June);
        CASE(July);
        CASE(August);
        CASE(September);
        CASE(October);
        CASE(November);
        CASE(December);
#undef CASE
    }
    return "std::chrono::month error";
}

} // anon

int main() {
    for (auto m : from_to{std::chrono::January, std::chrono::December}) {
        std::cout << to_cstr(m) << "\n";
    }
}
英文:

You could use a for-range loop.

I've de-templatized my from_to (inclusive) to make it easier to see the logic. Similar to Boost irange.

(I also have from_til (normal half-open range), after_to (uncommon half-open range), and after_til (uncommon betwixt-only range).)

#include &lt;chrono&gt;
#include &lt;iostream&gt;
#include &lt;stdexcept&gt;

namespace {

struct from_to {
    bool done{ false };
    std::chrono::month hot;
    std::chrono::month last;
    from_to(std::chrono::month first, std::chrono::month last_) : hot{first}, last{last_} {}
    auto operator*() const -&gt; std::chrono::month { return hot; }
    bool operator!=(from_to const&amp;) const { return not done; }
    void operator++() {
        if (done) throw std::logic_error(&quot;increment past end&quot;);
        if (hot == last) done = true;
        else ++hot;
    }
    auto begin() const -&gt; from_to const&amp; { return *this; }
    auto end() const -&gt; from_to const&amp; { return *this; }
};

auto to_cstr(std::chrono::month m) -&gt; char const* {
    switch (m.operator unsigned()) {
#define CASE(x) case std::chrono::x.operator unsigned(): return #x
        CASE(January);
        CASE(February);
        CASE(March);
        CASE(April);
        CASE(May);
        CASE(June);
        CASE(July);
        CASE(August);
        CASE(September);
        CASE(October);
        CASE(November);
        CASE(December);
#undef CASE
    }
    return &quot;std::chrono::month error&quot;;
}

} // anon

int main() {
    for (auto m : from_to{std::chrono::January, std::chrono::December}) {
        std::cout &lt;&lt; to_cstr(m) &lt;&lt; &quot;\n&quot;;
    }
}

huangapple
  • 本文由 发表于 2023年7月17日 23:19:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76705919.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定