ãã®è¨äºã¯C++ Advent Calendar 2022ã®5æ¥ç®ã®è¨äºã§ãã
åé¡ã§ãã次ã®ã³ã¼ãã«ã¯æªå®ç¾©åä½ãå°ãªãã¨ã1ã¤å«ã¾ãã¦ãã¾ããããã¯ä½ã§ãããï¼
#include <vector> #include <string> // ã©ããã§å®ç¾©ããã¦ããã¨ã㦠auto f() -> std::vector<std::string>; int main() { for (auto&& str : f()) { std::cout << str << '\n'; } for (auto&& c : f().at(0)) { std::cout << c << ' '; } }
以ä¸ããã®è¨äºã§ã¯ããã®f()
ããã³ãã³åå©ç¨ãã¾ããã宣è¨ã¯åæ²ãã¾ããã
çã
#include <vector> #include <string> auto f() -> std::vector<std::string>; int main() { for (auto&& str : f()) { std::cout << str << '\n'; } for (auto&& c : f().at(0)) { // ð ãã®è¡ // ^^^^^^^^^ std::cout << c << ' '; } }
f()
ã¯std::string
ãè¦ç´ ã«æã¤std::vector
ã®prvalueãè¿ãé¢æ°ã§ãããã®æ»ãå¤ã¯ä¸æãªãã¸ã§ã¯ãã§ããã®ã§ãå¤ã¨ãã¦åãããauto&&
ã§åãããªã©ãã¦å¯¿å½ã延é·ããå¿
è¦ãããã¾ããç¯å²for
æã§ãããã¯è¡ãããã®ã§ãæåã®for
æã¯åé¡ããã¾ããã
ã¨ãããã2ã¤ç®ã®for
æã¯f()
ã®æ»ãå¤ãããã®è¦ç´ ãå¼ãåºãã¦ãã¾ããããã§åé¡ãªã®ã¯ãè¦ç´ æ°ãä¸æãªãã¨ã§ã¯ããã¾ãããf().at()
ã®æ»ãå¤ã¯lvalueï¼std::string&
ï¼ã§ãããç¯å²for
ã¯ãã®çµæã®ãªãã¸ã§ã¯ãã ããä¿åãã¦ã«ã¼ããå»»ãã¦ããã¾ãããã®çµæãf()
ã®ç´æ¥ã®æ»ãå¤ã¯f().at(0)
ã®å¾ã§æ¨ã¦ãããå½ç¶ããããåå¾ããstd::string&
ã®åç
§ã¯ãã³ã°ãªã³ã°åç
§ã¨ãªãã¾ããããã¦ããã³ã°ãªã³ã°åç
§ã®ããããå©ç¨ã¯æªå®ç¾©åä½ã§ãã
ãªãï¼
ç¯å²for
æã¯ã·ã³ã¿ãã¯ã¹ã·ã¥ã¬ã¼ã§ããããã®å®æ
ã¯é常ã®for
æã«ããã³ã¼ãã¸å±éãããå½¢ã§å®è¡ããã¾ãã
ä¾ãã°ãè¦æ ¼ã«ããã¦ã¯ç¯å²for
ã®æ§æã¯ã¤ãã®ããã«è¦å®ããã¦ãã¾ã
for ( init-statement(opt) for-range-declaration : for-range-initializer ) statement
init-statement
ã¯for
ã®åæåå¼ï¼C++20 åæåå¼ãã¨ããªãç¯å²foræï¼ã§(opt)
ã¯çç¥å¯è½ã§ãããã¨ã表ãã¾ãã
for-range-declaration
ã¯for(auto&& v : r)
ã®auto&& v
ã®é¨åã§ãfor-range-initializer
ã¯r
ã®é¨åã§ãã
æ®ã£ãstatement
ã¯for
æã®æ¬ä½ã§ãã
ããã¦ãããã¯æ¬¡ã®ããã«å±éããã¦å®è¡ããã¾ã
{ init-statement(opt) auto &&range = for-range-initializer ; // ã¤ãã¬ã¼ã対象ãªãã¸ã§ã¯ãã®ä¿æ auto begin = begin-expr ; // std::begin(range)ç¸å½ auto end = end-expr ; // std::end(range)ç¸å½ for ( ; begin != end; ++begin ) { for-range-declaration = * begin ; statement } }
ã¤ã¾ãã¯ãã¾ãäºã¤ãã¬ã¼ã¿ã使ã£ãã«ã¼ãã«æ¸ãæãã¦ããããã§ããããã¦ãåé¡ã¯å±éå¾ãããã¯å ã®3è¡ç®ã«ããã¾ãã
auto &&range = for-range-initializer ;
ãã®å¼ã§ã¯ãauto&&
ã§ç¯å²for
ã®ã¤ãã¬ã¼ã対象ãªãã¸ã§ã¯ããåãã¦ãããããã«ãã£ã¦å·¦è¾ºå¤ãå³è¾ºå¤ãåãæ§æã§åãããããªããã¤å³è¾ºå¤ã«å¯¾ãã¦ã¯å¯¿å½å»¶é·ããªããã¾ããããã«å
ç¨ã®for
æããå®éã®å¼ããã¦ã¯ãã¦ã¿ã¦ã¿ã¾ãããã
// 1ã¤ç®ã®forãã auto &&range = f() ; // â ok // 2ã¤ç®ã®forãã auto &&range = f().at(0) ; // ð UB
2ã¤ç®ã®åæåå¼ã®ä½ãåé¡ãªã®ãã¨ããã¨ãå¤æ°range
ã«åãããã¦ããã®ã¯f().at(0)
ã®æ»ãå¤ï¼std::string&
ï¼ã§ãã£ã¦ãf()
ã®ç´æ¥ã®æ»ãå¤ã§ãã.at(0)
ã§åãåºããstd::string
ã®æ¬ä½ãææãããªãã¸ã§ã¯ãï¼std::vector<std::string>
ï¼ã¯ã©ãã«ãåãããã¦ããªãããã§ãã
ãã®ãããªä¸æãªãã¸ã§ã¯ãã®å¯¿å½ï¼lifetimeï¼ã¯ãã®å®å
¨å¼ã®çµããã«å°½ãããã¨è¦å®ããã¦ãã¦ãããã¯ã¨ã¦ãç°¡åã«ã¯ãã®å¼ãéãã;
ã§ããããªãã¡ããã®2ã¤ç®ã®åæåå¼ã§ã¯f()
ã®æ»ãå¤ã®å¯¿å½ã¯ãã®è¡ã§å°½ããããããåãåºããããã¹ã¦ã®åç
§ã¯ãã³ã°ãªã³ã°åç
§ã¨ãªãã¾ãã
ãããåé¿ããã«ã¯f()
ã®æ»ãå¤ãç´æ¥åãã¦ãããã®è¦ç´ ãåç
§ããã°ããã®ã§ãä¾ãã°ä¸è¨åæåå¼ã次ã®ããã«ããã°ããããã§ã
auto &&range0 = f(); // â ok auto &&range = range0.at(0) ; // â ok
ãã ããã¦ã¼ã¶ã¼ã³ã¼ãããã§ã¯å±éå¾ã®ã³ã¼ãããã®ããã«ãããã¨ã¯ã§ããªãã®ã§ãç¯å²for
ã®æ§æã§ã§ããç¯å²ã®äºãããªããã°ãªãã¾ããã
int main() { { // ç¯å²forã®å¤ã§åãã¦ãã auto tmp = f(); for (auto&& c : tmp.at(0)) { // â ok ... } } { // åæåå¼ãå©ç¨ãã for (auto tmp = f(); auto&& c : tmp.at(0)) { // â ok ... } } }
C++20ã§è¿½å ãããç¯å²for
æã«ãããåæåå¼ã¯ããã®åé¡ã®åé¿çã¨ãã¦å°å
¥ããããã®ã§ãããã¾ãã
ãã®ä»ã®ä¾
ããã ããªããã§ãããã§ããã§çµããããã§ãã®ã§ãããã«å¤ãªä¾ãç½®ãã¦ããã¾ãã
struct Person { std::vector<int> values; const auto& getValues() const { return values; } }; // prvalueãè¿ã auto createPerson() -> Person; int main() { for (auto elem : createPerson().values) { // â ok ... } for (auto elem : createPerson().getValues()) { // ð UB ... } }
ãªãã§ãã1ã¤ç®ã®for
æãokã«ãªããã§ããããã
#include <optional> #include <string> auto f() -> std::optional<std::string>; int main() { for (auto c : f().value()) { // ð UB ... } }
#include <optional> #include <string> struct S { std::string str; auto& value() && { return str; } auto&& rvalue() && { return std::move(str); } }; auto f() -> S; auto g() -> std::optional<std::string>; int main() { for (auto c : f().value()) { // â ok ... } for (auto c : f().rvalue()) { // ð UB ... } for (auto c : g().value()) { // ð UB ... } }
ãã®å·®ãä½ã§çã¾ãããã§ããããã»ã»ã»
#include <vector> #include <span> auto f() -> std::vector<int>; int main() { for (auto n : std::span{f().data(), 2}) { // ð UB ... } }
#include <variant> #include <string> auto f() -> std::variant<std::string, int>; int main() { for (auto c : std::get<std::string>(f())) { // ð UB ... } }
#include <tuple> #include <string> auto f() -> std::tuple<std::string, int>; int main() { for (auto c : std::get<0>(f())) { // ð UB ... } }
#include <map> #include <string> auto f() -> std::map<int, std::string>; int main() { for (auto c : f()[0]) { // ð UB ... } }
#include <coroutine> #include <string> // std::lazyã¯C++26äºå® auto f() -> std::lazy<std::string&>; std::lazy<> g() { for (auto c : co_await f()) { // ð UBï¼ã³ã«ã¼ãã³ãã¼ã«ã«ã®std::stringã¸ã®åç §ãè¿ãå ´åï¼ ... } }
ãã¦ããããã®ä¾ãè¦ã¦ããããã®åé¡ã®ããã³ã¼ãã絶対æ¸ããªãã¨æè¨ã§ããã§ããããï¼ç§ã¯ãã£ã¦ãã¾ãããã§ãã»ã»ã»
åå¦è
ãC++è¨èªãã®ãã®ã«ãã»ã©èå³ã®ãªãããã°ã©ããªã©ãç¯å²for
ã®ä»æ§ãç¥ããªãå ´åã¯ãã®åé¡ã«æ°ä»ããã¨ã¯ã§ããªãã§ãããããã®åé¡ãææ¡ããã»ã©è©³ãã人ã§ãããã®åé¡ã®èµ·ããå ´æãç¯å²for
ã«é è½ããã¦ãããã¨ã«ãã£ã¦ãã±ã£ã¨è¦ã¦æ°ã¥ããã¨ãé£ããå ´åãããã§ãããã
ãã®åé¡ã¯ç¯å²for
ã«åæååãæå®ã§ããããã«ããç¨åº¦ã§è§£æ±ºã§ãããããªãã®ã§ã¯ãªãããã確å®ãªè§£æ±ºçãå¿
è¦ãªåé¡ã§ãã
C++23ã«ããã解決
ãã®åé¡ã¯P2644R0ã®æ¡æã«ãã£ã¦ãC++23ã«ã¦ãããã解決ããã¾ãã
解決ã¯åç´ã§ãç¯å²for
ã®åæåå¼ï¼æ§æå®ç¾©ä¸ã®for-range-initializer
ï¼å
ã§ä½æããããã¹ã¦ã®ä¸æãªãã¸ã§ã¯ãã®å¯¿å½ã¯ç¯å²for
æã®å®äºï¼ã«ã¼ãçµäºï¼ã¾ã§å»¶é·ããããã¨è¦å®ãããããã«ãªãã¾ãã
å±éå¾ã®ã³ã¼ãã«ä½ãã¢ãããã¯ãªãã®ãå ããããã§ã¯ãªãããã®è¦å®ã«ãã£ã¦ãããå®è£
ããã³ã³ãã¤ã©ã§ã¯ç¯å²for
æã¯å®å
¨ã«å®å
¨ã«ãªããããã¾ã§ã«ç´¹ä»ãããããªUBã®ä¾ã®åé¡ã¯ãã¹ã¦è§£æ¶ï¼UBã§ã¯ãªããªãï¼ããã¾ãã
å®éã«ã©ã®ããã«ããããªãããã®ãã¯å®è£ å®ç¾©ã§ããCã®è¤åãªãã©ã«ã®ããã«ãããããããªãããå±éå¾ã³ã¼ããåæåå¼ãå解ãã¦ããããããã¾ããããããã«ããããã®å¤æ´ã«ãã£ã¦æ¢åã®ããã°ã©ã ã®åä½ãå£ãããã¨ã¯ãªãã¯ãã§ãã
ãªããããã¯C++23ã«å¯¾ããä¿®æ£ã§ãããC++20以åã®ãã¼ã¸ã§ã³ã«å¯¾ããæ¬ é¥å ±åã§ã¯ããã¾ãããå°ãªãã¨ãä»ã®ã¨ããã¯
ç´ä½æ²æ
ããããã¯ä½è«ã§ãã
ãã®åé¡ãææ¡ãããã®ã¯è¿å¹´ãã¨ããã¨ãããªããã¯ãªããå°ãªãã¨ã13å¹´åï¼2009å¹´ï¼ã«ã¯ææ¡ããã¦ãã¾ããï¼CWG Issue 900ï¼ããããC++11çå®ãããåã§ããã¾ãããã®å¾ããã³ãã³åæ§ã®Issueãæåºããã¦ããããã§ãã
ãªããã¯ç¥ãã¾ããããªããªã解決ããããªãã¾ã¾ããããããã®è§£æ±ºã®ããã®ææ¡ï¼P2012R0ï¼ãæåºãããã®ã2020å¹´ã®11æããã¯ãC++20ã«éã«åãããã®ãã¤ããææã§ããã
P2012ã¯EWGã®è°è«ã«ããã¦ãã®è§£æ±ºã®å¿ è¦æ§ã確èªããããã®ã®ããªãããã®å¾C++23ã«åãã¦P2012ãé²ããã¨ããã§ã³ã³ã»ã³ãµã¹ãå¾ããããææ¡ã®è¿½æ±ã¯åæ¢ããã¾ããã
ãã®å¾1å¹´ã»ã©åããç¡ãããã¯ãå¿ããããã®ãã¨èª°ããæã£ã¦ããé ã2022å¹´10æå¾åã«ãã¤ãã®WG21 NBï¼national bodyï¼ããã®C++23 CDï¼committee draftï¼ã«å¯¾ããNBã³ã¡ã³ãã¨å ±ã«ãP2644R0ãæåºããã¾ããã
P2644ã¯P2012ãè¸è¥²ãããã®ã§ãããã§ææ¡ããã¦ãã解決çã®ä¸ã¤ï¼ç¯å²for
ã®åæåå¼å
ã§çæãããä¸æãªãã¸ã§ã¯ãã®å¯¿å½ã延é·ããããã«è¦å®ããï¼ãåææ¡ãããã®ã§ãããããããã®ã¾ã¾2022å¹´11æã«Konaï¼ãã¯ã¤ï¼ã§è¡ãããWG21å
¨ä½ä¼è°ã«ããã¦ã¹ãã¼ãæ¡æãããC++23ã«é©ç¨ããããã¨ã«ãªãã¾ããã
P2644ã«ããã°ãP2012ãåæãå¾ãããªãã£ãã®ã¯æ¬è³ªçãªä¸æãªãã¸ã§ã¯ãã®å¯¿å½åé¡ã«ã¤ãã¦ãç¯å²for
ã ãã«ã¨ã©ã¾ããªãããåºç¯ãªè§£æ±ºçãã®ãã¾ãããããã ã£ãããã§ããã¤ã¾ããç¯å²for
ã®å±éå¾ã®ã³ã¼ãã«å¯¾ããã¢ãããã¯ãªå¯¾å¿ã¯å¿é¿ããããã¨ãã£ã¦æ¨æºæè¨ã«ããè¦å®ãå°æ¥ã®åºç¯ãªè§£æ±ºçã妨ãã¦ãã¾ãããã»ã»ã»ã¨èããããããã§ãã
ãããããã®ãããªè§£æ±ºçã¨ã¯P2623ã®ãããªãã®ãããã®ã§ãããããããã¯C++23ã«éã«åããã®ã§ããªããç¯å²for
ã®ãã®åé¡ã解決ããããã®æ½çã¯çµå±ä½ãåããã¦ãã¾ããã§ããããã¤ãããã®NBã³ã¡ã³ãåã³P2644ã¯ãã®ãããªç¶æ³ã«ãã³ããåããã¦æåºãããããã§ããP2644ã®ææ¡ã®å
容ã¯ãã©ããã£ã¦å¯¿å½ã延é·ããã ã¨ãããé¨åã¯ä½ãè¨ã£ã¦ããªããããå°æ¥çãªã½ãªã¥ã¼ã·ã§ã³ã妨ããªãããã«ããã¦ãã¾ãã
ã¨ããã§ãP2012ãP2644ãåãNicolai Josuttisããã¨ãã人ãã¡ã¤ã³ã®èè ã§ããããã¦è¨è¼ããã¦ããã¡ã¼ã«ã¢ãã¬ã¹ããå¯ããã«ãã®äººã¯ãã¤ãã®æ¹ã®ããã§ãã
åèæç®
- P2644R0 Get Fix of Broken Range-based for Loop Finally Done
- P2644 Get Fix of Broken Range-based for Loop Finally Done - cplusplus/papers
- P2012R0 Fix the range-based for loop, Rev0ix the range-based for loop - WG21æ次ææ¡ææ¸ãçºããï¼2020å¹´11æï¼
- P2644R0 Get Fix of Broken Range-based for Loop Finally Done - WG21æ次ææ¡ææ¸ãçºããï¼2022å¹´10æï¼