Document number: | PL22.16/12-0170 = WG21 N3480
Date: | 2012-11-03
Project: | Programming Language C++
Reference: | ISO/IEC IS 14882:2003
Reply to: | William M. Miller
| Edison Design Group, Inc.
| wmm@edg.com

## C++ Standard Core Language Active Issues, Revision 81

This document contains the C++ core language issues on which the Committee (J16 + WG21) has not yet acted, that is, issues with status "Ready," "Tentatively Ready," "Review," "Drafting," and "Open."

This document is part of a group of related documents that together describe the issues that have been raised regarding the C++ Standard. The other documents in the group are:

- Closed Issues List, which contains the issues which the Committee has decided are not defects in the International Standard, including a brief rationale explaining the reason for the decision.
- Defect Reports List, which contains the issues that have been categorized by the Committee as Defect Reports, as well as other issues accepted by the Committee, along with their proposed resolutions.
- Table of Contents, which contains a summary listing of all issues in numerical order.
- Index by Section, which contains a summary listing of all issues arranged in the order of the sections of the Standard with which they deal most directly.
- Index by Status, which contains a summary listing of all issues grouped by status.

Section references in this document reflect the section numbering of document WG21 N3376.

The purpose of these documents is to record the disposition of issues that have come before the Core Language Working Group of the ANSI (INCITS PL22.16) and ISO (WG21) C++ Standard Committee.

Some issues represent potential defects in the ISO/IEC IS 14882:2011 document and corrected defects in the earlier 2003 and 1998 documents; others refer to text in the working draft for the next revision of the C++ language and not to any Standard text. Issues are not necessarily formal ISO Defect Reports (DRs). While some issues will eventually be elevated to DR status, others will be disposed of in other ways. (See Issue Status below.)

The most current public version of this document can be found at http://www.open-std.org/jtc1/sc22/wg21. Requests for further information about these documents should include the document number, reference ISO/IEC 14882:2011, and be submitted to the InterNational Committee for Information Technology Standards (INCITS), 1250 Eye Street NW, Suite 200, Washington, DC 20005, USA.

Information regarding how to obtain a copy of the C++ Standard, join the Standard Committee, or submit an issue can be found in the C++ FAQ at http://www.comeaucomputing.com/csc/faq.html. Public discussion of the C++ Standard and related issues occurs on newsgroup comp.std.c++.

### Revision History

- Revision 81, 2012-11-03: Reflected the deliberations of the October, 2012 (Portland) meeting. Added new issues 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, and 1568.
- Revision 80, 2012-09-24: Added remaining descriptions omitted from issues added in revision 77. Corrected status of issues 915, 1313, 1399, and 1437. Changed the status of issues 616, 903, 1318, 1358, and 1402 in light of additional discussion. Incorporated the results of the drafting review teleconference held 2012-08-13. Moved issue 321 to "dup" status. Moved issue 591 to "open" status after the discussion in "dup" issue 1526. Added additional examples to issue 203. Added new issues 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, and 1559.
- Revision 79, 2012-02-27: Reflected deliberations at the February, 2012 (Kona) meeting. Added descriptions omitted from some issues added in revision 77. Moved issue 1427 to "NAD" status. Moved issue 1377 to "dup" status (with respect to issue 1279). Moved issue 1422 to "dup" status (with respect to issue 912). Added a new status, "concurrency", to track issues that will be considered and resolved by the Concurrency Working Group. Added new issues 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, and 1466.
- Revision 78, 2012-01-17: Reflected the results of the December 5, 2011 teleconference. Changed the status of issues 496, 675, 739, 1268, 1269, 1287, and 1312 from "ready" to "review" in response to further discussion of the proposed resolutions. Added new issues 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, and 1443.
- Revision 77, 2011-09-06: Reflected the deliberations of the August, 2011 (Bloomington) meeting. Added new issues 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, and 1369. (Note that many of the preceding issues are missing descriptions. These will be provided in the next revision of the issues list.)
- Revision 76, 2011-04-10: Reflected the results of the March 7, 2011 teleconference and the March, 2011 (Madrid) meeting, including adding a new status, "FDIS," for issues that are resolved in the draft advanced at that meeting for FDIS balloting. In respect for ISO rules governing work during the balloting process, no new issues have been included in this version of the list.
- Revision 75, 2011-02-28: Reflected results of two between-meetings teleconferences, including moving a number of issues to "tentatively ready" status. Added drafting for a number of issues and moved them to "review" status. Reopened issue 109 in light of recent discussion. Moved issue 1028 back to "open" status after further analysis. Moved issues 1109 and 1127 to "DR" status, as they had been overlooked in the results of the November, 2010 (Batavia) meeting. Added new issues 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, and 1246.
- Revision 74, 2010-11-29: Reflected deliberations at the November, 2010 (Batavia) meeting. Added new issues 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, and 1226.
- Revision 73, 2010-10-18: Moved issues 994 and 1058 back to "open" status for potential reconsideration. Added analysis to issue 1038. Moved issues 1125 and 1127 back to "drafting" status after further discussion revealed problems with the proposed resolution approved at the August, 2010 meeting. Moved issue 1167 to "review" status to allow consideration of extending the resolution to cover a new but related question. Reflected results of two between-meetings teleconferences, including moving a number of issues to "tentatively ready" status. Added new issues 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, and 1210,
- Revision 72, 2010-08-23: Reflected deliberations at the August, 2010 (Rapperswil) meeting. Added new issues 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, and 1173.
- Revision 71, 2010-08-07: Added new issues 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, and 1090.
- Revision 70, 2010-08-06: Reflected results of between-meetings teleconference, including moving a number of issues to "tentatively ready" status, updating proposed resolutions, and moving issues 341, 355, 472, and 529 to "drafting" status for more work. Changed issue 979 to "CD2" status, which was overlooked in the results of the March, 2010 meeting. Closed issues 1041, 1019, and 507 as duplicates of issues 924, 314, and 260, respectively.
- Revision 69, 2010-03-29: Reflected deliberations at the March, 2010 (Pittsburgh, PA) meeting. Placed all issues with "WP" status and newly-approved "DR" issues into "CD2" status, to reflect advancing the Final Committee Draft for balloting. Added new issues 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, and 1068.
- Revision 68, 2010-02-16: Reflected results of between-meeting teleconferences, including moving many issues to "tentatively ready" status and incorporating draft proposed resolutions for many others. Added new issues 999 and 1000.
- Revision 67, 2009-11-08: Reflected deliberations at the October, 2009 (Santa Cruz, CA) meeting. Added new issues 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, and 998.
- Revision 66, 2009-09-29: Incorporated a new status, "tentatively ready", for issues whose resolutions were reviewed and approved by teleconference between meetings. Changed issue 378 to "CD1" status, as it was resolved by the resolution of issue 276. Added new issues 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, and 971.
- Revision 65, 2009-08-03: Reflected deliberations from the Frankfurt, Germany (July, 2009) meeting. Added a new status, "concepts," for issues related to the concepts proposal that was removed from the working document and moved all concepts-related issues to that status, effectively closing them. Changed the presentation of proposed resolutions to use background colors in addition to font effects to identify changes (i.e., inserted and deleted text). Added new issues 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, and 948.
- Revision 64, 2009-06-19: Fixed incorrect cross-references in issues 867 and 868. Added proposed resolutions for issues 527, 587, 589, 604, 719, 732, and 770 and moved them to "review" status. Added discussion to issues 721, 760, 802, and 872. Added new issues 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, and 921.
- Revision 63, 2009-05-06: Closed issue 839 as a duplicate of issue 803. Added notes to the discussion of issues 325, 626, 667 690, 739, and 841. Moved issue 662 back to "open" status with additional discussion. Added new issues 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, and 888.
- Revision 62, 2009-03-23: Reflected deliberations from the Summit, NJ (March, 2009) meeting. Marked issues directly related to National Body comments on the 2008-10 Committee Draft with a tag identifying the relevant comment; the tag is both printed in the issue body and reflected in the "Index by Status" document. Added new issues 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, and 842.
- Revision 61, 2009-02-08: Provided a reference to a paper containing a proposed resolution for issues 695 and 699 and moved them to "review" status. Added new issues 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, and 766.
- Revision 60, 2008-12-09: Revised the resolution of issue 653 and moved to "review" status. Added new issues 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, and 748.
- Revision 59, 2008-10-05: Reflected deliberations from the San Francisco (September, 2008) meeting. Placed all issues with "WP" status and newly-approved "DR" issues into "CD1" status, to reflect advancing the Committee Draft for balloting. Added new proposed resolutions to issues 696, 704, and 705 and moved them to "review" status. Changed issue 265 to "dup" status in favor of issue 353, which was approved in 2003. Added new issues 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, and 723.
- Revision 58, 2008-08-25: Fixed some incorrect section references. Fixed the title of issue 692. Changed the status of issue 603 to "WP", as the paper that resolved it was approved in April, 2007. Moved issue 657 back to "review" status and added proposed wording. Added discussion to issues 693 and 697. Added or revised resolutions for issues 606, 614, 652, 685, and 694 and moved them to "review" status. Added new issues 704, 705, 706, 707, 708, and 709.
- Revision 57, 2008-07-27: Updated the status of issues 222, 309, and 632 to reflect actions at the June, 2008 meeting that were inadvertently omitted in the preceding revision. Added proposed wording for issue 683 and moved it to "review" status. Added new issues 697, 698, 699, 700, 701, 702, and 703.
- Revision 56, 2008-06-29: Reflected deliberations from the Sophia Antipolis (June, 2008) meeting. Added discussion to issues 507 and 527. Added proposed resolution for issue 653. Added new issues 695 and 696.
- Revision 55, 2008-05-18: Added proposed resolutions for issues 220, 257, 292, 341, 539, 554, 570, 571, 576, 597, 621, 624, 626, 633, 634, 639, and 642, and moved them to "review" status. Moved issue 155 to "dup" status in favor of issue 632, which was changed to "review" status in light of its connection with the initializer-list proposal. Moved issues 530 and 551 to "WP" status because they were resolved by the constexpr proposal. Moved issue 646 to "review" status because it appears to be "NAD". Changed issue 240 to "review" status (from "ready") in light of input from WG14 regarding a similar issue. Added new issues 685, 686, 687, 688, 689, 690, 691, 692, 693, and 694.
- Revision 54, 2008-03-17: Reflected deliberations from the Bellevue (February, 2008) meeting. Restructured references inside “definitions” sections (1.3 [intro.defs], 17.3 [definitions]) because the individual definitions are not sections. Returned issue 646 to "open" status (it was previously erroneously in "drafting" status). Moved issues 347, 512, and 236 to "review" status with a recommendation to close them as "NAD." Changed issues 220 and 256 back to "open" status and annotated them to indicate that they have been accepted by EWG and referred to CWG for action for C++0x. Changed issues 6 and 150 back to "open" status and annotated them to indicate that they have been accepted by EWG and referred to CWG for action, but not for C++0x. Closed issues 107, 168, 229, 294, and 359 as "NAD" to reflect the recommendation of EWG. Added new issues 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, and 684.
- Revision 53, 2008-02-03: Updated the proposed resolutions for issues 288 and 342. Updated the status of issues 199 and 430 to reflect actions at the Oxford (April, 2007) meeting. Added proposed resolutions and changed the status to "review" for issues 28, 111, 118, 141, 240, 276, 309, 355, 373, 378, 462, 485, 535, 574, 601, 608, 641, 645, and 651. Added new issues 667, 668, 669, 670, 671, and 672.
- Revision 52, 2007-12-09: Updated the status of issues 568 and 620 to reflect actions at the Toronto (July, 2007) meeting. Fixed a typographical error in the example for issue 606. Added new issues 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, and 666.
- Revision 51, 2007-10-09: Reflected deliberations from the Kona (October, 2007) meeting. Added new issues 652 and 653.
- Revision 50, 2007-09-09: Updated section reference numbers to use the numbering of the most recent working draft and added text identifying the document number of that draft at the beginning of each issues list document. Updated issue 475 with discussion regarding the point at which `std::uncaught_exception()` becomes `false`. Added new issues 642, 643, 644, 645, 646, 647, 648, 649, 650, and 651.
- Revision 49, 2007-08-05: Reflected deliberations from the Toronto (July, 2007) meeting. Added additional discussion to issues 219 and 339. Added new issues 637, 638, 639, 640, and 641.
- Revision 48, 2007-06-24: Added new issues 632, 633, 634, 635, and 636.
- Revision 47, 2007-05-06: Reflected deliberations from the Oxford (April, 2007) meeting. Added new issues 626, 627, 628, 629, 630, and 631.
- Revision 46, 2007-03-11: Added proposed wording to issue 495 and moved it to “review” status. Added new issues 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, and 625.
- Revision 45, 2007-01-14: Changed the status of issue 78 from TC1 to WP. Added new issues 603, 604, 605, 606, 607, 608, 609, 610, and 611.
- Revision 44, 2006-11-05: Reflected deliberations from the Portland (October, 2006) meeting. Added proposed wording for issues 288, 342, and 572, and moved them to “review” status. Added new issues 596, 597, 598, 599, 600, 601, and 602.
- Revision 43, 2006-09-09: Updated issues 218, 357, and 537 with additional discussion and proposed resolutions and moved them to “review” status; added issues 589, 590, 591, 592, 593, 594, and 595.
- Revision 42, 2006-06-23: Updated issues 408 and 561 with additional discussion; added a reference to a paper on the topic to issue 567; and added issues 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, and 588.
- Revision 41, 2006-04-22: Reflected deliberations from the Berlin (April, 2006) meeting. Added issues 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, and 577.
- Revision 40, 2006-02-24: Updated issue 540 to refer to paper J16/06-0022 = WG21 N1952 for its resolution. Updated issue 453 to note the need for additional drafting. Reopened issue 504 and broadened its scope to include object declarations as well. Updated issue 150 (in “extension” status) with additional commentary. Added issues 552, 553, 554, 555, 556, 557, 558, 559, 560, and 561.
- Revision 39, 2005-12-16: Updated issue 488 with additional discussion. Added issues 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, and 551.
- Revision 38, 2005-10-22: Reflected deliberations from the Mont Tremblant (October, 2005) meeting. Added isues 530, 531, 532, 533, 534, 535, 536, and 537.
- Revision 37, 2005-08-27: Added issues 523, 524, 525, 526, 527, 528, and 529.
- Revision 36, 2005-06-27: Reopened issue 484 for additional discussion. Added issues 517, 518, 519, 520, 521, and 522.
- Revision 35, 2005-05-01: Reflected deliberations from the Lillehammer (April, 2005) meeting. Updated issues 189 and 459 with additional discussion. Added new issues 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, and 516.
- Revision 34: 2005-03-06: Closed issue 471 as NAD; updated issues 58, 232, 339, 407, and 494 with additional discussion; and added new issues 498, 499, 500, 501, 502, and 503.
- Revision 33: 2005-01-14: Updated issue 36 with additional discussion. Added new issues 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, and 497.
- Revision 32: 2004-11-07: Reflected deliberations from the Redmond (October, 2004) meeting. Added new issues 475, 476, 477, 478, 479, 480, 481, 482, 483, and 484.
- Revision 31: 2004-09-10: Updated issue 268 with comments from WG14; added comments and changed the status of issue 451 back to “open”; added discussion to issues 334, 341, 385, 399, and 430; and added new issues 470, 471, 472, 473, and 474.
- Revision 30: 2004-04-09: Reflected deliberations from the Sydney (March, 2004) meeting. Added issues 461-469, updated issues 39, 86, 257, 291, 391, 389, 435, 436, 437, 439, 441, 442, 446, 450, 453, and 458.
- Revision 29: 2004-02-13: Added issues 441-460, updated issues 39, 291, 306, 319, 389, 394, 413, and 417.
- Revision 28: 2003-11-15: Reflected deliberations from the Kona (October, 2003) meeting. Added issues 435-438.
- Revision 27: 2003-09-19: Added new issues 412-434, updated issues 54, 301, 372, 382, 391, and 399.
- Revision 26: 2003-04-25: Reflected deliberations from the Oxford (April, 2003) meeting. Added new issues 402-411.
- Revision 25: 2003-03-03: Added new issues 390-401, updated issue 214.
- Revision 24: 2002-11-08: Reflected deliberations from the Santa Cruz (October, 2002) meeting. Added new issues 379-389.
- Revision 23: 2002-09-10: Added new issues 355-378, updated issue 298 and issue 214.
- Revision 22: 2002-05-10: Reflected deliberations from the Curacao (April, 2002) meeting. Added issues 342-354.
- Revision 21: 2002-03-11: Added new issues 314-341, updated issues 132, 214, 244, 245, 254, 255, 283.
- Revision 20: 2001-11-09: Reflected deliberations from the Redmond (October, 2001) meeting. Added issue 313.
- Revision 19: 2001-09-12: Added new issues 289-308, updated issues 222, 261, 270.
- Revision 18: 2001-05-19: Reflected deliberations from the Copenhagen (April, 2001) meeting. Added new issues 282-288.
- Revision 17: 2001-04-29: Added new issues 276-81.
- Revision 16: 2001-03-27: Updated issue 138 to discuss the interaction of using-declarations and "forward declarations." Noted a problem with the proposed resolution of issue 139. Added some new discussion to issue 115. Added proposed resolution for issue 160. Updated address of C++ FAQ. Added new issues 265-275.
- Revision 15: 2000-11-18: Reflected deliberations from the Toronto (October, 2000) meeting; moved the discussion of empty and fully-initialized const objects from issue 78 into new issue 253; added new issues 254-264.
- Revision 14: 2000-10-21: Added issues 246-252; added an extra question to issue 221 and changed its status back to "review."
- Revision 13: 2000-09-16: Added issues 229-245; changed status of issue 106 to "review" because of problem detected in proposal; added wording for issues 87 and 216 and moved to "review" status; updated discussion of issues 5, 78, 198, 203, and 222.
- Revision 12: 2000-05-21: Reflected deliberations from the Tokyo (April, 2000) meeting; added new issues 222-228.
- Revision 11, 2000-04-13: Added proposed wording and moved issues 62, 73, 89, 94, 106, 121, 134, 142, and 145 to "review" status. Moved issue 13 from "extension" to "open" status because of recent additional discussion. Added new issues 217-221.
- Revision 10, 2000-03-21: Split the issues list and indices into multiple documents. Added further discussion to issues 84 and 87. Added proposed wording and moved issues 1, 69, 85, 98, 105, 113, 132, and 178 to "review" status. Added new issues 207-216.
- Revision 9, 2000-02-23: Incorporated decisions from the October, 1999 meeting of the Committee; added issues 174 through 206.
- Revision 8, 1999-10-13: Minor editorial changes to issues 90 and 24; updated issue 89 to include a related question; added issues 169, 170, 171, 172, and 173.
- Revision 7, 1999-09-14: Removed unneeded change to 14.7.3 [temp.expl.spec] paragraph 9 from issue 24; changed issue 85 to refer to 3.4.4 [basic.lookup.elab]; added issues 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, and 168.
- Revision 6, 1999-05-31: Moved issue 72 to "dup" status; added proposed wording and moved issue 90 to "review" status; updated issue 98 with additional question; added issues 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, and 121.
- Revision 5, 1999-05-24: Reordered issues by status; added revision history; first public version.

### Issue status

Issues progress through various statuses as the Core Language Working Group and, ultimately, the full PL22.16 and WG21 committees deliberate and act. For ease of reference, issues are grouped in these documents by their status. Issues have one of the following statuses:

Open: The issue is new or the working group has not yet formed an opinion on the issue. If a Suggested Resolution is given, it reflects the opinion of the issue's submitter, not necessarily that of the working group or the Committee as a whole.

Drafting: Informal consensus has been reached in the working group and is described in rough terms in a Tentative Resolution, although precise wording for the change is not yet available.

Review: Exact wording of a Proposed Resolution is now available for an issue on which the working group previously reached informal consensus.

Ready: The working group has reached consensus that a change in the working draft is required, the Proposed Resolution is correct, and the issue is ready to forward to the full Committee for ratification.

Tentatively Ready: Like "ready" except that the resolution was produced and approved by a subset of the working group membership between meetings. Persons not participating in these between-meeting activities are encouraged to review such resolutions carefully and to alert the working group with any problems that may be found.

DR: The full Committee has approved the item as a proposed defect report. The Proposed Resolution in an issue with this status reflects the best judgment of the Committee at this time regarding the action that will be taken to remedy the defect; however, the current wording of the Standard remains in effect until such time as a Technical Corrigendum or a revision of the Standard is issued by ISO.

Accepted: Like a DR except that the issue concerns the wording of the current Working Paper rather than that of the current International Standard.

TC1: A DR issue included in Technical Corrigendum 1. TC1 is a revision of the Standard issued in 2003.

CD1: A DR issue not resolved in TC1 but included in Committee Draft 1. CD1 was advanced for balloting at the September, 2008 WG21 meeting.

CD2: A DR issue not resolved in CD1 but included in the Final Committee Draft advanced for balloting at the March, 2010 WG21 meeting.

FDIS: A DR issue not resolved in the FCD but included in the Final Draft International Standard advanced for balloting at the March, 2011 WG21 meeting.

DRWP: A DR issue whose resolution is reflected in the current Working Paper. The Working Paper is a draft for a future version of the Standard.

WP: An Accepted issue whose resolution is reflected in the current Working Paper.

Dup: The issue is identical to or a subset of another issue, identified in a Rationale statement.

NAD: The working group has reached consensus that the issue is not a defect in the Standard. A Rationale statement describes the working group's reasoning.

Extension: The working group has reached consensus that the issue is not a defect in the Standard but is a request for an extension to the language. The working group expresses no opinion on the merits of an issue with this status; however, the issue will be maintained on the list for possible future consideration as an extension proposal.

Concepts: The issue relates to the “Concepts” proposal that was removed from the working paper at the Frankfurt (July, 2009) meeting and hence is no longer under consideration.

Concurrency: The issue deals with concurrency and is to be handled by the Concurrency Working Group within WG21.

### Issues with "Ready" Status

#### 616. Definition of “indeterminate value”

Section: 1.3 [intro.defs] Status: ready Submitter: Bjarne Stroustrup Date: 2 February 2007

The C++ Standard uses the phrase “indeterminate value” without defining it. C99 defines it as “either an unspecified value or a trap representation.” Should C++ follow suit?

In addition, 4.1 [conv.lval] paragraph 1 says that applying the lvalue-to-rvalue conversion to an “object [that] is uninitialized” results in undefined behavior; this should be rephrased in terms of an object with an indeterminate value.

Proposed resolution (October, 2012):

1. Change 4.1 [conv.lval] paragraphs 1 and 2 as follows (including changing the running text of paragraph 2 into bullets):

> A glvalue (3.10 [basic.lval]) of a non-function, non-array type `T` can be converted to a prvalue.53 If `T` is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not an object of type `T` and is not an object of a type derived from `T`, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior. If `T` is a non-class type, the type of the prvalue is the cv-unqualified version of `T`. Otherwise, the type of the prvalue is `T`.54

> When an lvalue-to-rvalue conversion occurs in an unevaluated operand or a subexpression thereof (Clause 5 [expr]) the value contained in the referenced object is not accessed. In all other cases, the result of the conversion is determined according to the following rules:

> - If `T` is (possibly cv-qualified) `std::nullptr_t`, the result is a null pointer constant (4.10 [conv.ptr]).

> - Otherwise, if the glvalue `T` has a class type, the conversion copy-initializes a temporary of type `T` from the glvalue and the result of the conversion is a prvalue for the temporary.

> - Otherwise, if the object to which the glvalue refers contains an invalid pointer value (3.7.4.2 [basic.stc.dynamic.deallocation], 3.7.4.3 [basic.stc.dynamic.safety]), the behavior is implementation-defined.

> - Otherwise, if `T` is a (possibly cv-qualified) unsigned character type (3.9.1 [basic.fundamental]), and the object to which the glvalue refers contains an indeterminate value (5.3.4 [expr.new], 8.5 [dcl.init], 12.6.2 [class.base.init]), and that object does not have automatic storage duration or the glvalue was the operand of a unary `&` operator or it was bound to a reference, the result is an unspecified value. [Footnote: The value may be different each time the lvalue-to-rvalue conversion is applied to the object. An `unsigned char` object with indeterminate value allocated to a register might trap. —end footnote]

> - Otherwise, if the object to which the glvalue refers contains an indeterminate value, the behavior is undefined.

> - Otherwise, if the glvalue has (possibly cv-qualified) type `std::nullptr_t`, the prvalue result is a null pointer constant (4.10 [conv.ptr]). Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.

2. Change 5.2.5 [expr.ref] paragraph 4 second bullet as follows:

- If `E2` is a static data member...

- ...If `E1` is an lvalue, then `E1.E2` is an lvalue; if `E1` is an xvalue, then otherwise `E1.E2` is an xvalue; otherwise, it is a prvalue. Let the notation...

- If `E2` is a (possibly overloaded) member function...

3. Change 5.5 [expr.mptr.oper] paragraph 6 as follows:

> ...The result of a `.*` expression whose second operand is a pointer to a data member is of the same value category (3.10 [basic.lval]) as its first operand an lvalue if the first operand is an lvalue and an xvalue otherwise. The result of a `.*` expression whose second operand is a pointer to a member function...

This resolution also resolves issues 129, 240, 312, and 1013.

Additional note (August, 2012):

It was observed that the phrase in the fourth bullet of the change to 4.1 [conv.lval] paragraph 2 that reads “is not a local variable” should probably be changed to “does not have automatic storage duration,” because objects with static storage duration are zero-initialized and thus cannot have an indeterminate value. The issue was returned to "review" status for discussion of this point.

#### 1476. Definition of user-defined type

Section: 1.3 [intro.defs] Status: ready Submitter: Loïc Joly Date: 2012-03-08

The Standard uses the phrase, “user-defined type,” but it is not clear what it is intended to mean. For example, 17.6.4.2.1 [namespace.std] paragraph 1 says,

> A program may add a template specialization for any standard library template to namespace `std` only if the declaration depends on a user-defined type...

Are types defined in the Standard library “user-defined?”

7.1.6.2 [dcl.type.simple] paragraph 2 says,

> The `auto` specifier is a placeholder for a type to be deduced (7.1.6.4 [dcl.spec.auto]). The other simple-type-specifiers specify either a previously-declared user-defined type or one of the fundamental types (3.9.1 [basic.fundamental]).

implying that all non-fundamental types are “user-defined.”

A definition is needed, as well as a survey of uses of the term to ensure consistency with the definition.

Proposed resolution (October, 2012):

1. Change 7.1.6.2 [dcl.type.simple] paragraph 2 as follows:

> The `auto` specifier is a placeholder for a type to be deduced (7.1.6.4 [dcl.spec.auto]). The other simple-type-specifiers specify either a previously-declared user-defined type, a type determined from an expression, or one of the fundamental types (3.9.1 [basic.fundamental]). Table 10 summarizes the valid combinations of simple-type-specifiers and the types they specify.

2. Change 4 [conv] paragraph 4 as follows:

> [Note: For user-defined class types, user-defined conversions are considered as well; see 12.3 [class.conv]. In general, an implicit conversion sequence (13.3.3.1 [over.best.ics]) consists of a standard conversion sequence followed by a user-defined conversion followed by another standard conversion sequence. —end note]

3. Change the example in 13.3.1.2 [over.match.oper] paragraph 1 as follows:

      ...
      void f(void) {
        const char* p= "one" + "two";  // ill-formed because neither
                                       // operand has user-defined class or enumeration type
        int I = 1 + 1;                 // Always evaluates to 2 even if
                                       // user-defined class or enumeration types exist which
                                       // would perform the operation.
      }

#### 129. Stability of uninitialized auto variables

Section: 1.9 [intro.execution] Status: ready Submitter: Nathan Myers Date: 26 June 1999

Does the Standard require that an uninitialized auto variable have a stable (albeit indeterminate) value? That is, does the Standard require that the following function return `true`?

        bool f() {
            unsigned char i;  // not initialized
            unsigned char j = i;
            unsigned char k = i;
            return j == k;    // true iff "i" is stable
        }

3.9.1 [basic.fundamental] paragraph 1 requires that uninitialized `unsigned char` variables have a valid value, so the initializations of `j` and `k` are well-formed and required not to trap. The question here is whether the value of `i` is allowed to change between those initializations.

Mike Miller: 1.9 [intro.execution] paragraph 10 says,

> An instance of each object with automatic storage duration (3.7.3 [basic.stc.auto] ) is associated with each entry into its block. Such an object exists and retains its last-stored value during the execution of the block and while the block is suspended...

I think that the most reasonable way to read this is that the only thing that is allowed to change the value of an automatic (non-volatile?) value is a "store" operation in the abstract machine. There are no "store" operations to `i` between the initializations of `j` and `k`, so it must retain its original (indeterminate but valid) value, and the result of the program is well-defined.

The quibble, of course, is whether the wording "last-stored value" should be applied to a "never-stored" value. I think so, but others might differ.

Tom Plum: 7.1.6.1 [dcl.type.cv] paragraph 8 says,

> [Note: `volatile` is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See 1.9 [intro.execution] for detailed semantics. In general, the semantics of `volatile` are intended to be the same in C++ as they are in C. ]

>From this I would infer that non-volatile means "shall not be changed by means undetectable by an implementation"; that the compiler is entitled to safely cache accesses to non-volatile objects if it can prove that no "detectable" means can modify them; and that therefore i shall maintain the same value during the example above.

Nathan Myers: This also has practical code-generation consequences. If the uninitialized auto variable lives in a register, and its value is really unspecified, then until it is initialized that register can be used as a temporary. Each time it's "looked at" the variable has the value that last washed up in that register. After it's initialized it's "live" and cannot be used as a temporary any more, and your register pressure goes up a notch. Fixing the uninit'd value would make it "live" the first time it is (or might be) looked at, instead.

Mike Ball: I agree with this. I also believe that it was certainly never my intent that an uninitialized variable be stable, and I would have strongly argued against such a provision. Nathan has well stated the case. And I am quite certain that it would be disastrous for optimizers. To ensure it, the frontend would have to generate an initializer, because optimizers track not only the lifetimes of variables, but the lifetimes of values assigned to those variables. This would put C++ at a significant performance disadvantage compared to other languages. Not even Java went this route. Guaranteeing defined behavior for a very special case of a generally undefined operation seems unnecessary.

Proposed resolution (February, 2012):

This issue is resolved by the resolution of issue 616.

#### 1472. odr-use of reference variables

Section: 3.2 [basic.def.odr] Status: ready Submitter: Richard Smith Date: 2012-03-01

We have a special case in 3.2 [basic.def.odr] paragraph 2 that variables which satisfy the requirements for appearing in a constant expression are not odr-used if the lvalue-to-rvalue conversion is immediately applied. This special case only applies to objects, and thus does not apply to variables of reference type. This inconsistency seems strange, and there is implementation divergence:

      int n;
      void f() {
       constexpr int &r = n;
       [] { return r; }; // error: r is odr-used but not captured
      }

This code is accepted by g++ but rejected by clang. Should `r` be odr-used here?

Proposed resolution (October, 2012):

Change 3.2 [basic.def.odr] paragraph 3 as follows:

> A variable `x` whose name appears as a potentially-evaluated expression `ex` is odr-used unless `x` is an object that satisfies the requirements for appearing in a constant expression (5.19 [expr.const]) and, if `x` is an object, `ex` is an element of the set of potential results of an expression `e`, where either the lvalue-to-rvalue conversion (4.1 [conv.lval]) is applied to `e`, or `e` is a discarded-value expression (Clause 5 [expr]). `this` is odr-used...

#### 1511. `const volatile` variables and the one-definition rule

Section: 3.2 [basic.def.odr] Status: ready Submitter: Richard Smith Date: 2012-06-18

One of the criteria in 3.2 [basic.def.odr] paragraph 6 for when a entity is allowed to have multiple definitions is:

> in each definition of `D`, corresponding names, looked up according to 3.4 [basic.lookup], shall refer to an entity defined within the definition of `D`, or shall refer to the same entity, after overload resolution (13.3 [over.match]) and after matching of partial template specialization (14.8.3 [temp.over]), except that a name can refer to a `const` object with internal or no linkage if the object has the same literal type in all definitions of `D`, and the object is initialized with a constant expression (5.19 [expr.const]), and the value (but not the address) of the object is used, and the object has the same value in all definitions of `D`; and

This wording is possibly not sufficiently clear for an example like:

      const volatile int n = 0;
      inline int get() { return n; }

Presumably this code could not appear in multiple translation units, because the requirement that `n` “has the same value in all definitions” cannot be satisfied (the value of a volatile variable can change “by means undetectable by the implementation,” per 7.1.6.1 [dcl.type.cv] paragraph 7, so the value of `n` might be different in each translation unit). However, it might be good to make it explicit that “a `const` object” is not intended to apply to a volatile-qualified object.

Other points that were raised during the discussion of this issue were that it would probably be better to rephrase “the value (but not the address) of the object is used” in terms of the odr-use of the object, as well as questioning why a `const volatile` variable implicitly has internal linkage.

Proposed resolution (October, 2012):

1. Change 3.2 [basic.def.odr] paragraph 6 as follows:

> There can be more than one definition...

> - ...

> - in each definition of `D`, corresponding names, looked up according to 3.4 [basic.lookup], shall refer to an entity defined within the definition of `D`, or shall refer to the same entity, after overload resolution (13.3 [over.match]) and after matching of partial template specialization (14.8.3 [temp.over]), except that a name can refer to a non-volatile `const` object with internal or no linkage if the object has the same literal type in all definitions of `D`, and the object is initialized with a constant expression (5.19 [expr.const]), and the value (but not the address) of the object is used not odr-used, and the object has the same value in all definitions of `D`; and

> - ...

2. Change 3.5 [basic.link] paragraph 3 as follows:

> A name having namespace scope (3.3.6 [basic.scope.namespace]) has internal linkage if it is the name of

> - a variable, function or function template that is explicitly declared `static`; or,

> - a non-volatile variable that is explicitly declared `const` or `constexpr` and neither explicitly declared `extern` nor previously declared to have external linkage; or

> - a data member of an anonymous union.

#### 1310. What is an “acceptable lookup result?”

Section: 3.4.3.1 [class.qual] Status: ready Submitter: Jason Merrill Date: 2011-05-06

In 3.4.3.1 [class.qual] paragraph 2,

> In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class `C`:

> - if the name specified after the nested-name-specifier, when looked up in `C`, is the injected-class-name of `C` (Clause 9 [class]), or

> - in a using-declaration (7.3.3 [namespace.udecl]) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id's template-name in the last component of the nested-name-specifier,

> the name is instead considered to name the constructor of class `C`.

it is not clear what constitutes “an acceptable lookup result.” For instance, is

      struct S { } *sp = new S::S;

well-formed?

The intent of the wording was that `S::S` would refer to the constructor except in lookups that ignore the names of functions, e.g., in elaborated-type-specifiers and nested-name-specifiers. There doesn't seem to be a good reason to allow a qualified-id naming the injected-class-name. The alternative, i.e., only to find the constructor in a declarator, complicates parsing because the determination of whether the name is a type or a function would require lookahead.

Proposed resolution (August, 2012):

Change 3.4.3.1 [class.qual] paragraph 2 as follows:

> In a lookup in which the constructor is an acceptable lookup result function names are not ignored [Footnote: Lookups in which function names are ignored include names appearing in a nested-name-specifier, an elaborated-type-specifier, or a base-specifier. —end footnote] and the nested-name-specifier nominates a class `C`:

> - if the name specified after the nested-name-specifier, when looked up in `C`, is the injected-class-name of C (Clause 9 [class]), or

> - in a using-declaration (7.3.3 [namespace.udecl]) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id's template-name in the last component of the nested-name-specifier,

> the name is instead considered to name the constructor of class `C`...

#### 1489. Is value-initialization of an array constant initialization?

Section: 3.6.2 [basic.start.init] Status: ready Submitter: Steve Adamczyk Date: 2012-03-29

According to 3.6.2 [basic.start.init] paragraph 2,

> Constant initialization is performed:

> - ...

> - if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.

Presumably this would include a value-initialization (i.e., with no expressions) such as

      int a[1000]{};

However, we have recently clarified the degenerate cases of other similar rules referencing “every,” so it wouldn't hurt to be more explicit here.

Proposed resolution (October, 2012):

Change 3.6.2 [basic.start.init] paragraph 2 as follows:

> Constant initialization is performed:

> - ...

> - if an object with static or thread storage duration is not initialized by a constructor call and if either the object is value-initialized or every full-expression that appears in its initializer is a constant expression.

#### 312. “use” of invalid pointer value not defined

Section: 3.7.4.2 [basic.stc.dynamic.deallocation] Status: ready Submitter: Martin von Loewis Date: 20 Sep 2001

3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 4 mentions that the effect of using an invalid pointer value is undefined. However, the standard never says what it means to 'use' a value.

There are a number of possible interpretations, but it appears that each of them leads to undesired conclusions:

1. A value is 'used' in a program if a variable holding this value appears in an expression that is evaluated. This interpretation would render the sequence

          int *x = new int(0);
          delete x;
          x = 0;

   into undefined behaviour. As this is a common idiom, this is clearly undesirable.
2. A value is 'used' if an expression evaluates to that value. This would render the sequence

          int *x = new int(0);
          delete x;
          x->~int();

   into undefined behaviour; according to 5.2.4 [expr.pseudo], the variable x is 'evaluated' as part of evaluating the pseudo destructor call. This, in turn, would mean that all containers (23 [containers]) of pointers show undefined behaviour, e.g. 23.3.5.4 [list.modifiers] requires to invoke the destructor as part of the `clear()` method of the container.

If any other meaning was intended for 'using an expression', that meaning should be stated explicitly.

(See also issue 623.)

Proposed resolution (February, 2012):

This issue is resolved by the resolution of issue 616.

#### 496. Is a volatile-qualified type really a POD?

Section: 3.9 [basic.types] Status: ready Submitter: John Maddock Date: 30 Dec 2004

In 3.9 [basic.types] paragraph 10, the standard makes it quite clear that volatile qualified types are PODs:

> Arithmetic types (3.9.1 [basic.fundamental]), enumeration types, pointer types, and pointer to member types (3.9.2 [basic.compound]), and cv-qualified versions of these types (3.9.3 [basic.type.qualifier]) are collectively called scalar types. Scalar types, POD-struct types, POD-union types (clause 9 [class]), arrays of such types and cv-qualified versions of these types (3.9.3 [basic.type.qualifier]) are collectively called POD types.

However in 3.9 [basic.types] paragraph 3, the standard makes it clear that PODs can be copied “as if” they were a collection of bytes by `memcpy`:

> For any POD type `T`, if two pointers to `T` point to distinct `T` objects `obj1` and `obj2`, where neither `obj1` nor `obj2` is a base-class subobject, if the value of `obj1` is copied into `obj2`, using the `std::memcpy` library function, `obj2` shall subsequently hold the same value as `obj1`.

The problem with this is that a volatile qualified type may need to be copied in a specific way (by copying using only atomic operations on multithreaded platforms, for example) in order to avoid the “memory tearing” that may occur with a byte-by-byte copy.

I realise that the standard says very little about volatile qualified types, and nothing at all (yet) about multithreaded platforms, but nonetheless this is a real issue, for the following reason:

The forthcoming TR1 will define a series of traits that provide information about the properties of a type, including whether a type is a POD and/or has trivial construct/copy/assign operations. Libraries can use this information to optimise their code as appropriate, for example an array of type `T` might be copied with a `memcpy` rather than an element-by-element copy if `T` is a POD. This was one of the main motivations behind the type traits chapter of the TR1. However it's not clear how volatile types (or POD's which have a volatile type as a member) should be handled in these cases.

Notes from the April, 2005 meeting:

It is not clear whether the volatile qualifier actually guarantees atomicity in this way. Also, the work on the memory model for multithreading being done by the Evolution Working Group seems at this point likely to specify additional semantics for volatile data, and that work would need to be considered before resolving this issue.

Proposed resolution, October, 2012:

1. Change 3.9 [basic.types] paragraph 9 as follows:

> ...Scalar types, trivially copyable class types (Clause 9 [class]), arrays of such types, and cv-qualified non-volatile const-qualified versions of these types (3.9.3 [basic.type.qualifier]) are collectively called trivially copyable types. Scalar types, trivial class types...

2. Change 7.1.6.1 [dcl.type.cv] paragraphs 6-7 as follows:

> What constitutes an access to an object that has volatile-qualified type is implementation-defined. If an attempt is made to refer to an object defined with a volatile-qualified type through the use of a glvalue with a non-volatile-qualified type, the program behavior is undefined.

> [Note: `volatile` is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. Furthermore, for some implementations, `volatile` might indicate that special hardware instructions are required to access the object. See 1.9 [intro.execution] for detailed semantics. In general, the semantics of `volatile` are intended to be the same in C++ as they are in C. —end note]

3. Change 12.8 [class.copy] paragraph 12 as follows:

> A copy/move constructor for class `X` is trivial if it is not user-provided, its declared parameter type is the same as if it had been implicitly declared, and if

> - class `X` has no virtual functions (10.3 [class.virtual]) and no virtual base classes (10.1 [class.mi]), and

> - class `X` has no non-static data members of volatile-qualified type, and

> - ...

4. Change 12.8 [class.copy] paragraph 25 as follows:

> A copy/move assignment operator for class `X` is trivial if it is not user-provided, its declared parameter type is the same as if it had been implicitly declared, and if

> - class `X` has no virtual functions (10.3 [class.virtual]) and no virtual base classes (10.1 [class.mi]), and

> - class `X` has no non-static data members of volatile-qualified type, and

> - ...

#### 1405. `constexpr` and mutable members of literal types

Section: 3.9 [basic.types] Status: ready Submitter: Richard Smith Date: 2011-10-21

Currently, literal class types can have mutable members. It is not clear whether that poses any particular problems with constexpr objects and constant expressions, and if so, what should be done about it.

Proposed resolution (February, 2012):

Change 5.19 [expr.const] paragraph 2 as follows:

- ...

- an lvalue-to-rvalue conversion (4.1 [conv.lval]) unless it is applied to

- a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or

- a glvalue of literal type that refers to a non-volatile object defined with `constexpr`, or that refers to a non-mutable sub-object of such an object, or

- a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;

- ...

#### 1515. Modulo 2n arithmetic for implicitly-unsigned types

Section: 3.9.1 [basic.fundamental] Status: ready Submitter: Sean Hunt Date: 2012-07-03

According to 3.9.1 [basic.fundamental] paragraph 4,

> Unsigned integers, declared `unsigned`, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.

It is not clear whether this wording intentionally excludes types like `char16_t` and `char32_t` (and, possibly, types `char` and `wchar_t`, if those types are unsigned in a given implementation), since the `unsigned` keyword is not used in their declaration.

Proposed resolution (October, 2012):

Change 3.9.1 [basic.fundamental] paragraph 4 as follows:

> Unsigned integers, declared `unsigned`, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.46

#### 1539. Definition of “character type”

Section: 3.9.1 [basic.fundamental] Status: ready Submitter: Beman Dawes Date: 2012-08-15

The term character type is used in the Standard without definition. It should be defined; however, the use of the term is divergent between the core and library clauses: in the former, it means narrow character types, while in the latter it includes `wchar_t`, `char16_t`, and `char32_t`, so care must be taken in ensuring that no inadvertent changes are implied.

Proposed resolution (October, 2012):

1. Change 3.7.4.3 [basic.stc.dynamic.safety] paragraph 1 as follows:

> A traceable pointer object is

> - ...

> - a sequence of elements in an array of narrow character type (3.9.1 [basic.fundamental]), where the size and alignment of the sequence match those of some object pointer type.

2. Change 3.9.1 [basic.fundamental] paragraph 1 as follows:

> Objects declared as characters (char) shall be large enough to store any member of the implementation's basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation-defined whether a `char` object can hold negative values. Characters can be explicitly declared `unsigned` or `signed`. Plain `char`, `signed char`, and `unsigned char` are three distinct types, collectively called narrow character types. A `char`, a `signed char`, and an `unsigned char` occupy the same amount of storage and have the same alignment requirements (3.11 [basic.align]); that is, they have the same object representation. For narrow character types, all bits of the object representation participate in the value representation. For unsigned narrow character types, all possible bit patterns of the value representation represent numbers. These requirements do not hold for other types. In any particular implementation, a plain `char` object can take on either the same values as a `signed char` or an `unsigned char`; which one is implementation-defined.

3. Change 3.11 [basic.align] paragraph 6 as follows:

> The alignment requirement of a complete type can be queried using an `alignof` expression (5.3.6 [expr.alignof]). Furthermore, the types `char`, `signed char`, and `unsigned char` narrow character types (3.9.1 [basic.fundamental]) shall have the weakest alignment requirement. [Note: This enables the narrow character types to be used as the underlying type for an aligned memory area (7.6.2 [dcl.align]). —end note]

4. Change 8.5.2 [dcl.init.string] paragraph 1 as follows:

> A `char` array (whether plain `char`, `signed char`, or `unsigned char`) An array of narrow character type (3.9.1 [basic.fundamental]), `char16_t` array, `char32_t` array, or `wchar_t` array can be initialized by a narrow character string literal, `char16_t` string literal, `char32_t` string literal, or wide string literal, respectively, or by an appropriately-typed string literal enclosed in braces (2.14.5 [lex.string]). Successive characters of the value of the string literal initialize the elements of the array. [Example:

#### 240. Uninitialized values and undefined behavior

Section: 4.1 [conv.lval] Status: ready Submitter: Mike Miller Date: 8 Aug 2000

4.1 [conv.lval] paragraph 1 says,

> If the object to which the lvalue refers is not an object of type `T` and is not an object of a type derived from `T`, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

I think there are at least three related issues around this specification:

1. Presumably assigning a valid value to an uninitialized object allows it to participate in the lvalue-to-rvalue conversion without undefined behavior (otherwise the number of programs with defined behavior would be vanishingly small :-). However, the wording here just says "uninitialized" and doesn't mention assignment.

2. There's no exception made for `unsigned char` types. The wording in 3.9.1 [basic.fundamental] was carefully crafted to allow use of `unsigned char` to access uninitialized data so that `memcpy` and such could be written in C++ without undefined behavior, but this statement undermines that intent.

3. It's possible to get an uninitialized rvalue without invoking the lvalue-to-rvalue conversion. For instance:

               struct A {
                   int i;
                   A() { } // no init of A::i
               };
               int j = A().i;  // uninitialized rvalue

   There doesn't appear to be anything in the current IS wording that says that this is undefined behavior. My guess is that we thought that in placing the restriction on use of uninitialized objects in the lvalue-to-rvalue conversion we were catching all possible cases, but we missed this one.

In light of the above, I think the discussion of uninitialized objects ought to be removed from 4.1 [conv.lval] paragraph 1. Instead, something like the following ought to be added to 3.9 [basic.types] paragraph 4 (which is where the concept of "value" is introduced):

> Any use of an indeterminate value (5.3.4 [expr.new], 8.5 [dcl.init], 12.6.2 [class.base.init]) of any type other than `char` or `unsigned char` results in undefined behavior.

John Max Skaller:

`A().i` had better be an lvalue; the rules are wrong. Accessing a member of a structure requires it be converted to an lvalue, the above calculation is 'as if':

        struct A {
            int i;
            A *get() { return this; }
        };
        int j = (*A().get()).i;

and you can see the bracketed expression is an lvalue.

A consequence is:

        int &j= A().i; // OK, even if the temporary evaporates

`j` now refers to a 'destroyed' value. Any use of `j` is an error. But the binding at the time is valid.

Proposed Resolution (November, 2006):

1. Add the indicated words to 3.9 [basic.types] paragraph 4:

   > ... For trivial types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values. Any use of an indeterminate value (5.3.4 [expr.new], 8.5 [dcl.init], 12.6.2 [class.base.init]) of a type other than `unsigned char` results in undefined behavior.

2. Change 4.1 [conv.lval] paragraph 1 as follows:

   > If the object to which the lvalue refers is not an object of type `T` and is not an object of a type derived from `T`, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

Additional note (May, 2008):

The C committee is dealing with a similar issue in their DR336. According to this analysis, they plan to take almost the opposite approach to the one described above by augmenting the description of their version of the lvalue-to-rvalue conversion. The CWG did not consider that access to an unsigned char might still trap if it is allocated in a register and needs to reevaluate the proposed resolution in that light. See also issue 129.

Proposed resolution (February, 2012):

This issue is resolved by the resolution of issue 616.

#### 1013. Uninitialized `std::nullptr_t` objects

Section: 4.1 [conv.lval] Status: ready Submitter: Miller Date: 2009-12-10

According to 4.1 [conv.lval] paragraph 1, an lvalue-to-rvalue conversion on an uninitialized object produces undefined behavior. Since there is only one “value” of type `std::nullptr_t`, an lvalue-to-rvalue conversion on a `std::nullptr_t` glvalue does not need to fetch the value from storage. Is there any need for undefined behavior in this case?

Proposed resolution (February, 2012):

This issue is resolved by the resolution of issue 616.

#### 1557. Language linkage of converted lambda function pointer

Section: 5.1.2 [expr.prim.lambda] Status: ready Submitter: Scott Meyers Date: 2012-09-19

5.1.2 [expr.prim.lambda] paragraph 6 does not specify the language linkage of the function type of the closure type's conversion function.

Proposed resolution (October, 2012):

Change 5.1.2 [expr.prim.lambda] paragraph 6 as follows:

> The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C++ language linkage (7.5 [dcl.link]). having the same parameter and return types as the closure type's function call operator. The value returned...

#### 1516. Definition of “virtual function call”

Section: 5.2.2 [expr.call] Status: ready Submitter: Nikolay Ivchenkov Date: 2012-07-05

The terms “virtual function call” and “virtual call” are used in the Standard but are not defined.

Proposed resolution (August, 2012):

Change 5.2.2 [expr.call] paragraph 1 as follows:

> If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider (10.3 [class.virtual]) in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.

#### 1320. Converting scoped enumerations to `bool`

Section: 5.2.9 [expr.static.cast] Status: ready Submitter: Jonathan Wakely Date: 2011-05-18

The specification of `static_cast` (5.2.9 [expr.static.cast]) does not describe conversion of a scoped enumeration value to `bool`. Presumably it should be handled as for unscoped enumerations, with a zero value becoming `false` and a non-zero value becoming `true`.

Proposed resolution (August, 2012):

Change 5.2.9 [expr.static.cast] paragraph 9 as follows:

> A value of a scoped enumeration type (7.2 [dcl.enum]) can be explicitly converted to an integral type. The When that type is cv `bool`, the resulting value is `false` if the original value is zero and `true` for all other values. For the remaining integral types, the value is unchanged if the original value can be represented by the specified type. Otherwise, the resulting value is unspecified.

#### 1412. Problems in specifying pointer conversions

Section: 5.2.9 [expr.static.cast] Status: ready Submitter: Nikolay Ivchenkov Date: 2011-11-01

The definedness of various pointer conversions (see 5.2.10 [expr.reinterpret.cast] paragraph 7, 9.2 [class.mem] paragraph 20, 5.2.9 [expr.static.cast] paragraph 13) relies on the properties of the types involved, such as whether they are standard-layout types and their intrinsic alignment. This creates contradictions and unnecessary unspecified behavior when the actual values of the pointer involved would actually permit the operations. Recasting the specification in terms of the memory model instead of the types of the objects provides a more coherent specification.

Proposed resolution (February, 2012):

1. Change 4.10 [conv.ptr] paragraph 2 as follows:

> A prvalue of type “pointer to cv `T`,” where `T` is an object type, can be converted to a prvalue of type “pointer to cv `void`”. The result of converting a “pointer to cv `T`” non-null pointer value of a pointer to object type to a “pointer to cv void” points to the start of the storage location where the object of type `T` resides, as if the object is a most derived object (1.8 [intro.object]) of type `T` (that is, not a base class subobject) represents the address of the same byte in memory as the original pointer value. The null pointer value is converted to the null pointer value of the destination type.

2. Change 5.2.9 [expr.static.cast] paragraph 13 as follows:

> A prvalue of type “pointer to cv1 `void`” can be converted to a prvalue of type “pointer to cv2 `T`,” where `T` is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. The null pointer value is converted to the null pointer value of the destination type. If the original pointer value represents the address `A` of a byte in memory and `A` satisfies the alignment requirement of `T`, then the resulting pointer value represents the same address as the original pointer value, that is, `A`. The result of any other such pointer conversion is unspecified. A value of type pointer to object converted to “pointer to cv `void`” and back, possibly with different cv-qualification, shall have its original value...

3. Change 5.2.10 [expr.reinterpret.cast] paragraph 7 as follows:

> An object pointer can be explicitly converted to an object pointer of a different type.70 When a prvalue `v` of object pointer type “pointer to `T1`” is converted to the object pointer type “pointer to cv `T2`”, the result is `static_cast<cv T2*>(static_cast<cv void*>(v))` if both `T1` and `T2` are standard-layout types (3.9 [basic.types]) and the alignment requirements of `T2` are no stricter than those of `T1`, or if either type is `void`. Converting a prvalue of type “pointer to `T1`” to the type “pointer to `T2`” (where `T1` and `T2` are object types and where the alignment requirements of `T2` are no stricter than those of `T1`) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

#### 1553. `sizeof` and xvalue bit-fields

Section: 5.3.3 [expr.sizeof] Status: ready Submitter: Richard Smith Date: 2012-09-13

According to 5.3.3 [expr.sizeof] paragraph 1,

> The `sizeof` operator shall not be applied... to an lvalue that designates a bit-field.

Xvalues can also designate bit-fields and thus should presumably be addressed here as well.

Proposed resolution (October, 2012):

Change 5.3.3 [expr.sizeof] paragraph 1 as follows:

> The `sizeof` operator yields the number of bytes in the object representation of its operand. The operand is either an expression, which is an unevaluated operand (Clause 5 [expr]), or a parenthesized type-id. The `sizeof` operator shall not be applied to an expression that has function or incomplete type, to an enumeration type whose underlying type is not fixed before all its enumerators have been declared, to the parenthesized name of such types, or to an lvalue a glvalue that designates a bit-field. `sizeof(char)`...

#### 1464. Negative array bound in a new-expression

Section: 5.3.4 [expr.new] Status: ready Submitter: Mike Miller Date: 2012-02-12

Currently, 5.3.4 [expr.new] paragraph 7 requires that an attempt to allocate an array with a negative length be diagnosed:

> If the value of that expression is less than zero or such that the size of the allocated object would exceed the implementation-defined limit, or if the new-initializer is a braced-init-list for which the number of initializer-clauses exceeds the number of elements to initialize, no storage is obtained and the new-expression terminates by throwing an exception of a type that would match a handler (15.3 [except.handle]) of type `std::bad_array_new_length` (18.6.2.2 [new.badlength]).

Checking for a negative bound will be lost, however, upon the adoption of paper N3323, as the expression will be converted to `std::size_t`, an unsigned type. Although the result of this conversion will likely also cause the check to fail (and will always do so when scaled by an element size larger than 1), it is not inconceivable that an implementation could provide a heap that capable of providing more than half the addressable range of `std::size_t`, and a request for a character array (with an element size of 1) with a negative bound close to `LONG_MIN` (assuming `std::size_t` is `unsigned long`) might actually succeed.

The wording of 5.3.4 [expr.new] paragraph 7 should be changed so that the test for a negative bound is applied to the value before conversion to `std::size_t`, or some other mechanism should be invented to preserve the check for a negative bound.

Additional note (August, 2012):

The goal for addressing this issue should be that an attempt to use an invalid bound (negative, greater than the maximum allowed, or more than the number implied by the initializer) will be ill-formed when the bound is a compile-time constant and will result in an exception otherwise.

Proposed resolution (October, 2012):

1. Change 3.9.2 [basic.compound] paragraph 2 as follows:

> These methods of constructing types can be applied recursively; restrictions are mentioned in 8.3.1 [dcl.ptr], 8.3.4 [dcl.array], 8.3.5 [dcl.fct], and 8.3.2 [dcl.ref]. Constructing a type such that the number of bytes in its object representation exceeds the maximum value representable in the type `std::size_t` (18.2 [support.types]) is ill-formed.

2. Change 5.3.4 [expr.new] paragraph 7 as follows:

> The expression in a noptr-new-declarator is erroneous if:

> - the expression is of non-class type and its value before converting to `std::size_t` is less than zero;

> - the expression is of class type and its value before application of the second standard conversion (13.3.3.1.2 [over.ics.user]) [Footnote: If the conversion function returns a signed integer type, the second standard conversion converts to the unsigned type `std::size_t` and thus thwarts any attempt to detect a negative value afterwards. —end footnote] is less than zero;

> - its value is such that the size of the allocated object would exceed the implementation-defined limit (annex B [implimits]); or

> - the new-initializer is a braced-init-list and the number of array elements for which initializers are provided (including the terminating `'\0'` in a string literal (2.14.5 [lex.string])) exceeds the number of elements to initialize.

> If the expression, after converting to `std::size_t`, is a core constant expression and the expression is erroneous, the program is ill-formed. Otherwise, a new-expression with an erroneous expression does not call an allocation function and terminates by throwing an exception of a type that would match a handler (15.3 [except.handle]) of type `std::bad_array_new_length` (18.6.2.2 [new.badlength]). When the value of the expression in a noptr-new-declarator is zero, the allocation function is called to allocate an array with no elements. If the value of that expression is less than zero or such that the size of the allocated object would exceed the implementation-defined limit, or if the new-initializer is a braced-init-list for which the number of initializer-clauses exceeds the number of elements to initialize, no storage is obtained and the new-expression terminates by throwing an exception of a type that would match a handler (15.3 [except.handle]) of type `std::bad_array_new_length` (18.6.2.2 [new.badlength]).

(This resolution also resolves issue 1559.)

#### 1559. String too long in initializer list of new-expression

Section: 5.3.4 [expr.new] Status: ready Submitter: John Spicer Date: 2012-09-21

According to 5.3.4 [expr.new] paragraph 7,

> if the new-initializer is a braced-init-list for which the number of initializer-clauses exceeds the number of elements to initialize, no storage is obtained and the new-expression terminates by throwing an exception of a type that would match a handler (15.3 [except.handle]) of type `std::bad_array_new_length` (18.6.2.2 [new.badlength]).

This wording does not, but presumably should, require an exception to be thrown in a case like

      void f() {
        int x = 3;
        new char[x]{"abc"};
      }

(See also issue 1464.)

Proposed resolution (October, 2012):

This issue is resolved by the resolution of issue 1464.

#### 1504. Pointer arithmetic after derived-base conversion

Section: 5.7 [expr.add] Status: ready Submitter: Loïc Joly Date: 2012-05-20

The current wording is not sufficiently clear that a pointer to a base class subobject of an array element cannot be used in pointer arithmetic.

Proposed resolution (October, 2012):

Add the following as a new paragraph before 5.7 [expr.add] paragraph 7:

> For addition or subtraction, if the expressions `P` or `Q` have type “pointer to cv `T`", where `T` is different from the cv-unqualified array element type, the behavior is undefined. [Note: In particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type. —end note]

> If the value `0` is added to or subtracted...

#### 1550. Parenthesized throw-expression operand of conditional-expression

Section: 5.16 [expr.cond] Status: ready Submitter: Nikolay Ivchenkov Date: 2012-09-04

The current wording of 5.16 [expr.cond] paragraph 2 says,

> If either the second or the third operand has type `void`, then the lvalue-to-rvalue (4.1 [conv.lval]), array-to-pointer (4.2 [conv.array]), and function-to-pointer (4.3 [conv.func]) standard conversions are performed on the second and third operands, and one of the following shall hold:

> - The second or the third operand (but not both) is a throw-expression (15.1 [except.throw]); the result is of the type of the other and is a prvalue.

> - Both the second and the third operands have type `void`; the result is of type `void` and is a prvalue. [Note: This includes the case where both operands are throw-expressions. —end note]

A parenthesized throw-expression is a primary-expression, not a throw-expression. Should a parenthesized throw-expression be considered a throw-expression for this purpose?

Proposed resolution (October, 2012):

Change 5.16 [expr.cond] paragraph 2 as follows:

> If either the second or the third operand has type `void`, then the lvalue-to-rvalue (4.1 [conv.lval]), array-to-pointer (4.2 [conv.array]), and function-to-pointer (4.3 [conv.func]) standard conversions are performed on the second and third operands, and one of the following shall hold:

> - The second or the third operand (but not both) is a (possibly parenthesized) throw-expression (15.1 [except.throw]); the result is of the type and value category of the other and is a prvalue.

> - ...

(This resolution also resolves issue 1560.)

#### 1560. Gratuitous lvalue-to-rvalue conversion in conditional-expression with throw-expression operand

Section: 5.16 [expr.cond] Status: ready Submitter: Nikolay Ivchenkov Date: 2012-09-04

A glvalue appearing as one operand of a conditional-expression in which the other operand is a throw-expression is converted to a prvalue, regardless of how the conditional-expression is used:

> If either the second or the third operand has type `void`, then the lvalue-to-rvalue (4.1 [conv.lval]), array-to-pointer (4.2 [conv.array]), and function-to-pointer (4.3 [conv.func]) standard conversions are performed on the second and third operands, and one of the following shall hold:

> - The second or the third operand (but not both) is a throw-expression (15.1 [except.throw]); the result is of the type of the other and is a prvalue.

This seems to be gratuitous and surprising.

Proposed resolution (October, 2012):

This issue is resolved by the resolution of issue 1550.

#### 1527. Assignment from braced-init-list

Section: 5.17 [expr.ass] Status: ready Submitter: Mike Miller Date: 2012-07-23

According to 5.17 [expr.ass] paragraph 9,

> A braced-init-list may appear on the right-hand side of

> - an assignment to a scalar...

> - an assignment defined by a user-defined assignment operator, in which case the initializer list is passed as the argument to the operator function.

Presumably the phrase “user-defined” is not intended to forbid an example like

      struct A {
        A();
        A ( std::initializer_list<int> ) ;
      };
      void f() {
        A a;
        a = {37};
      }

which relies on an implicitly-declared assignment operator.

Proposed resolution (August, 2012):

Change 5.17 [expr.ass] paragraph 9 as follows:

> A braced-init-list may appear on the right-hand side of

> - an assignment to a scalar, in which case the initializer list shall have at most a single element. The meaning of `x={v}`, where `T` is the scalar type of the expression `x`, is that of `x=T(v)` except that no narrowing conversion (8.5.4) is allowed. The meaning of `x={}` is `x=T()`.

> - an assignment defined by a user-defined assignment operator to an object of class type, in which case the initializer list is passed as the argument to the assignment operator function selected by overload resolution (13.5.3 [over.ass], 13.3 [over.match]).

#### 1538. C-style cast in braced-init-list assignment

Section: 5.17 [expr.ass] Status: ready Submitter: Daniel Krügler Date: 2012-08-14

According to 5.17 [expr.ass] paragraph 9,

> The meaning of `x={v}`, where `T` is the scalar type of the expression `x`, is that of `x=T(v)` except that no narrowing conversion (8.5.4 [dcl.init.list]) is allowed. The meaning of `x={}` is `x=T()`.

This definition adds a gratuitous C-style cast to the right-hand operand, inadvertently allowing such things as base-to-derived conversions and circumvention of access checking.

Proposed resolution (October, 2012):

Change 5.17 [expr.ass] paragraph 9 as follows:

> The meaning of `x={v}`, where `T` is the scalar type of the expression `x`, is that of `x=T(v)` except that no narrowing conversion (8.5.4 [dcl.init.list]) is allowed `x=T{v}`. The meaning of `x={}` is `x=T() `x=T{}``.

#### 1456. Address constant expression designating the one-past-the-end address

Section: 5.19 [expr.const] Status: ready Submitter: Richard Smith Date: 2012-01-14

Currently an address constant expression cannot designate the address one past the end of an array. This seems unfortunate.

Proposed resolution (August, 2012):

Change 5.19 [expr.const] paragraph 3 as follows:

> ...An address constant expression is a prvalue core constant expression of pointer type that evaluates to the address of an object with static storage duration, to the address one past the last element of an array with static storage duration, to the address of a function, or to a null pointer value, or a prvalue core constant expression of type `std::nullptr_t`...

#### 1535. `typeid` in core constant expressions

Section: 5.19 [expr.const] Status: ready Submitter: Richard Smith Date: 2012-08-10

One of the criteria in 5.19 [expr.const] paragraph 2 for disqualifying an expression from being a constant expression is:

- > a typeid expression (5.2.8 [expr.typeid]) whose operand is of a polymorphic class type;

on the basis that a runtime test for the dynamic type is inconsistent with a constant expression. However, it is only glvalues of polymorphic type that require a runtime test; type-ids and prvalues with a polymorphic type could (and should) be permitted in constant expressions.

Proposed resolution (October, 2012):

Change 5.19 [expr.const] paragraph 2 as follows:

- ...

- a typeid expression (5.2.8 [expr.typeid]) whose operand is a glvalue of a polymorphic class type;

#### 1537. Optional compile-time evaluation of constant expressions

Section: 5.19 [expr.const] Status: ready Submitter: John Spicer Date: 2012-08-14

According to the note in 5.19 [expr.const] paragraph 4,

> [Note: Although in some contexts constant expressions must be evaluated during program translation, others may be evaluated during program execution. Since this International Standard imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution.

With the advent of narrowing rules, which require the compiler to evaluate constant expressions in more contexts than was the case in C++03 in order to determine whether an expression is well formed or not, this wording is not sufficiently clear in stating that even in cases where the computation must be done at compile time, the implementation is free to use the result of a runtime calculation rather than preserving the one computed at compile time.

Proposed resolution (October, 2012):

Change 5.19 [expr.const] paragraph 4 as follows:

> [Note: Although in some contexts constant expressions must be evaluated during program translation, others may be evaluated during program execution. Since this International Standard imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution. [Footnote: Nonetheless, implementations are encouraged to provide consistent results, irrespective of whether the evaluation was actually performed during translation and/or during program execution. —end footnote] [Example:...

#### 1442. Argument-dependent lookup in the range-based `for`

Section: 6.5.4 [stmt.ranged] Status: ready Submitter: Mike Miller Date: 2012-01-16

It is not clear whether the reference to argument-dependent lookup in 6.5.4 [stmt.ranged] paragraph 1 bullet 3 should be “pure” argument-dependent lookup (with no unqualified name lookup component) or the usual lookup that is invoked when argument-dependent lookup is done, i.e., unqualified lookup, potentially augmented by the associated namespaces.

Proposed resolution (October, 2012):

Change 6.5.4 [stmt.ranged] paragraph 1 bullet 3 as follows:

- otherwise, begin-expr and end-expr are `begin(__range)` and `end(__range)`, respectively, where `begin` and `end` are looked up with argument-dependent lookup in the associated namespaces (3.4.2 [basic.lookup.argdep]). For the purposes of this name lookup, namespace `std` is an associated namespace. [Note: Ordinary unqualified lookup (3.4.1 [basic.lookup.unqual]) is not performed. —end note]

#### 1541. cv `void` return types

Section: 6.6.3 [stmt.return] Status: ready Submitter: Sean Hunt Date: 2012-08-21

According to 6.6.3 [stmt.return] paragraph 3,

> A return statement with neither an expression nor a braced-init-list can be used only in functions that do not return a value, that is, a function with the return type `void`, a constructor (12.1 [class.ctor]), or a destructor (12.4 [class.dtor]).

However, paragraph 3 allows a return type of cv `void` in cases where the expression in the `return` statement has type `void`. Should paragraph 2 follow suit?

Proposed resolution (October, 2012):

Change 6.6.3 [stmt.return] paragraph 2 as follows:

> A return statement with neither an expression nor a braced-init-list can be used only in functions that do not return a value, that is, a function with the return type cv `void`, a constructor (12.1 [class.ctor]), or a destructor (12.4 [class.dtor]). A return statement with an expression of non-void type...

#### 1544. Linkage of member of unnamed namespace

Section: 7.1.1 [dcl.stc] Status: ready Submitter: Nikolay Ivchenkov Date: 2012-08-24

There is a contradiction in the specification of the linkage of members of the unnamed namespace, for example

      namespace {
        int x;
      }

According to 3.5 [basic.link] paragraph 4,

> An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage. A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of

> - a variable; or

> - ...

which would give `x` internal linkage. However, 7.1.1 [dcl.stc] paragraph 7 says,

> A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared `const`.

This would give `x` external linkage. (This appears to have been a missed edit from the resolution of issue 1113.)

Proposed resolution (October, 2012):

Delete 7.1.1 [dcl.stc] paragraph 7:

> A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared `const`. Objects declared `const` and not explicitly declared `extern` have internal linkage.

#### 1437. `alignas` in alias-declaration

Section: 7.1.3 [dcl.typedef] Status: ready Submitter: Daveed Vandevoorde Date: 2012-01-02

Consider the following:

        struct S { int i; };
        using A alignas(alignof(long long)) = S;

7.6.2 [dcl.align] paragraph 1 allows an alignment-specifier to be applied to the declaration of a class or enumeration type, which `A` arguably is. The specification should be clarified to indicate that such a usage is not permitted, however.

Proposed resolution (October, 2012):

Change 7.6.2 [dcl.align] paragraph 1 as follows:

> An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, the formal parameter of a catch clause an exception-declaration (15.3 [except.handle]), or a variable declared with the `register` storage class specifier. An alignment-specifier may also be applied to the declaration of a class or enumeration type or definition of a class (in an elaborated-type-specifier (7.1.6.3 [dcl.type.elab]) or class-head (Clause 9 [class]), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively (7.2 [dcl.enum])). An alignment-specifier with an ellipsis is a pack expansion (14.5.3 [temp.variadic]).

#### 1358. Unintentionally ill-formed `constexpr` function template instances

Section: 7.1.5 [dcl.constexpr] Status: ready Submitter: Richard Smith Date: 2011-08-16

The permission granted implementations in 7.1.5 [dcl.constexpr] paragraph 5 to diagnose definitions of `constexpr` functions that can never be used in a constant expression should not apply to an instantiated `constexpr` function template.

Notes from the August, 2011 meeting:

The CWG also decided to treat the following example under this issue, although it does not involve a function template:

        int f();   // not constexpr
        struct A {
          int m;
          constexpr A(int i = f()) : m(i) { }
        };
        struct B {
          A a;
        } b;

This is ill-formed, no diagnostic required, because the defaulted default constructor of `B` will be declared `constexpr` but can never be invoked in a constant expression. See issue 1360.

Proposed resolution (February, 2012):

1. Change 7.1.5 [dcl.constexpr] paragraph 5 as follows:

> ... —end example]

> For a non-template, non-defaulted `constexpr` function, if no function argument values exist such that the function invocation substitution would produce a constant expression (5.19 [expr.const]), the program is ill-formed; no diagnostic required. For a non-template, non-defaulted, non-inheriting `constexpr` constructor, if no argument values exist such that after function invocation substitution, every constructor call and full-expression in the mem-initializers would be a constant expression (including conversions), the program is ill-formed; no diagnostic required. For a `constexpr` function template or member function of a class template, if no instantiation would be well-formed when considered as a non-template `constexpr` function, the program is ill-formed; no diagnostic required. [Example:...

2. Delete 7.1.5 [dcl.constexpr] paragraph 6:

> If the instantiated template specialization of a `constexpr` function template or member function of a class template would fail to satisfy the requirements for a `constexpr` function or `constexpr` constructor, that specialization is not a `constexpr` function or `constexpr` constructor. [Note: If the function is a member function it will still be `const` as described below. —end note] If no specialization of the template would yield a `constexpr` function or `constexpr` constructor, the program is ill-formed; no diagnostic required.

Additional notes, February, 2012:

The proposed resolution inadvertently removes the provision allowing specializations of `constexpr` templates to violate the requirements of 7.1.5 [dcl.constexpr]. It is being retained in "drafting" status pending additional work.

Proposed resolution (October, 2012):

Change 7.1.5 [dcl.constexpr] paragraphs 5-6 as follows:

> ...For a non-template, non-defaulted `constexpr` function, if no function argument values exist such that the function invocation substitution would produce a constant expression (5.19 [expr.const]), the program is ill-formed; no diagnostic required. For a non-template, non-defaulted, non-inheriting `constexpr` constructor, if no argument values exist such that after function invocation substitution, every constructor call and full-expression in the mem-initializers would be a constant expression (including conversions), the program is ill-formed; no diagnostic required. [Example: ... —end example]

> If the instantiated template specialization of a `constexpr` function template or member function of a class template would fail to satisfy the requirements for a `constexpr` function or `constexpr` constructor, that specialization is not still a `constexpr` function or `constexpr` constructor, even though a call to such a function cannot appear in a constant expression. [Note: If the function is a member function it will still be `const` as described below. —end note] If no specialization of the template would yield satisfy the requirements for a `constexpr` function or `constexpr` constructor when considered as a non-template function or constructor, the program template is ill-formed; no diagnostic required.

#### 1475. Errors in `[[carries_dependency]]` example

Section: 7.6.4 [dcl.attr.depend] Status: ready Submitter: Stephan Lavavej Date: 2012-03-06

The example in 7.6.4 [dcl.attr.depend] paragraph 4 reads,

      /* Translation unit A. */

      struct foo { int* a; int* b; };
      std::atomic<struct foo *> foo_head[10];
      int foo_array[10][10];

      [[carries_dependency]] struct foo* f(int i) {
        return foo_head[i].load(memory_order_consume);
      }

      [[carries_dependency]] int g(int* x, int* y) {
        return kill_dependency(foo_array[*x][*y]);
      }

      /* Translation unit B. */

      [[carries_dependency]] struct foo* f(int i);
      [[carries_dependency]] int* g(int* x, int* y);

      int c = 3;

      void h(int i) {
        struct foo* p;

        p = f(i);
        do_something_with(g(&c, p->a));
        do_something_with(g(p->a, &c));
      }

There appear to be two errors in this example. First, `g` is declared as returning `int` in TU A but `int*` in TU B. Second, paragraph 6 says,

> Function `g`'s second argument has a `carries_dependency` attribute

but that is not reflected in the example.

Proposed resolution (August, 2012):

1. Change the example in 7.6.4 [dcl.attr.depend] paragraph 4 as follows:

      /* Translation unit A. */

      struct foo { int* a; int* b; };
      std::atomic<struct foo *> foo_head[10];
      int foo_array[10][10];

      [[carries_dependency]] struct foo* f(int i) {
        return foo_head[i].load(memory_order_consume);
      }

      [[carries_dependency]] int g(int* x, int* y [[carries_dependency]]) {
        return kill_dependency(foo_array[*x][*y]);
      }

      /* Translation unit B. */

      [[carries_dependency]] struct foo* f(int i);
      [[carries_dependency]] int* int g(int* x, int* y [[carries_dependency]]);

      int c = 3;

      void h(int i) {
        struct foo* p;
        p = f(i);
        do_something_with(g(&c, p->a));
        do_something_with(g(p->a, &c));
      }

2. Change 7.6.4 [dcl.attr.depend] paragraph 6 as follows:

> Function `g`'s second argument parameter has a `carries_dependency` attribute, but its first argument parameter does not. Therefore, function `h`'s first call to `g` carries a dependency into `g`, but its second call does not. The implementation might need to insert a fence prior to the second call to `g`.

#### 1528. Repeated cv-qualifiers in declarators

Section: 8 [dcl.decl] Status: ready Submitter: Richard Smith Date: 2012-07-23

There is no restriction against repeated cv-qualifiers in declarators, although there is (in 7.1.6 [dcl.type] paragraph 2) for those appearing in a decl-specifier-seq. However, most or all current implementations reject such code. Is a change needed?

Proposed resolution (October, 2012):

Change 7.1.6.1 [dcl.type.cv] paragraph 1 as follows:

> There are two cv-qualifiers, `const` and `volatile`. Each cv-qualifier shall appear at most once in a cv-qualifier-seq. If a cv-qualifier appears in a decl-specifier-seq, the init-declarator-list of the declaration shall not be empty. [Note:...

#### 1435. template-id as the declarator for a class template constructor

Section: 8.3 [dcl.meaning] Status: ready Submitter: Johannes Schaub Date: 2011-12-24

The status of a declaration like the following is unclear:

      template<typename T> struct A {
        A<T>();
      };

8.3 [dcl.meaning] paragraph 1 appears to say that it is not allowed, but it is not clear.

Proposed resolution (October, 2012):

1. Change 8.3 [dcl.meaning] paragraph 1 as follows:

> A list of declarators appears after an optional (Clause 7 [dcl.dcl]) decl-specifier-seq (7.1 [dcl.spec]). Each declarator contains exactly one declarator-id; it names the identifier that is declared. An unqualified-id occurring in a declarator-id shall be a simple identifier except for the declaration of some special functions (12.1 [class.ctor], 12.3 [class.conv], 12.4 [class.dtor], 13.5 [over.oper]) and for the declaration of template specializations or partial specializations (14.7 [temp.spec]). A declarator-id shall not...

2. Change 12.1 [class.ctor] paragraph 1 as follows:

> Constructors do not have names. A special declarator syntax is used to declare or define the constructor. The syntax uses:

> - an optional decl-specifier-seq in which each decl-specifier is either a function-specifier or `constexpr`,

> - the constructor's class name, and

> - a parameter list

> in that order. In such a declaration, optional parentheses around the constructor class name are ignored. A declaration of a constructor uses a function declarator (8.3.5 [dcl.fct]) of the form

> ptr-declarator `(` parameter-declaration-clause `)` exception-specificationopt attribute-specifier-seqopt

> where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:

> - in a member-declaration that belongs to the member-specification of a class but is not a friend declaration (11.3 [class.friend]), the id-expression is the injected-class-name (Clause 9 [class]) of the immediately-enclosing class;

> - in a member-declaration that belongs to the member-specification of a class template but is not a friend declaration, the id-expression is a class-name that names the current instantiation (14.6.2.1 [temp.dep.type]) of the immediately-enclosing class template; or

> - in a declaration at namespace scope or in a friend declaration, the id-expression is a qualified-id that names a constructor (3.4.3.1 [class.qual]).

> The class-name shall not be a typedef-name. In a constructor declaration, each decl-specifier in the optional decl-specifier-seq shall be `friend`, `inline`, `explicit`, or `constexpr`. [Example:...

3. Delete 12.1 [class.ctor] paragraph 3:

> A typedef-name shall not be used as the class-name in the declarator-id for a constructor declaration.

4. Change 12.1 [class.ctor] paragraph 4 as follows:

> A constructor shall not be `virtual` (10.3 [class.virtual]) or `static` (9.4 [class.static]). A constructor can be invoked for a `const`, `volatile` or `const volatile` object. A constructor shall not be declared `const`, `volatile`, or `const volatile` (9.3.2 [class.this]). `const` and `volatile` semantics (7.1.6.1 [dcl.type.cv]) are not applied on an object under construction. They come into effect when the constructor for the most derived object (1.8 [intro.object]) ends. A constructor shall not be declared with a ref-qualifier.

5. Change 12.1 [class.ctor] paragraph 9 as follows:

> No return type (not even `void`) shall be specified for a constructor. A `return` statement in the body of a constructor shall not specify a return value. The address of a constructor shall not be taken.

6. Change 12.4 [class.dtor] paragraphs 1-2 as follows:

> A special declarator syntax using an optional function-specifier (7.1.2 [dcl.fct.spec]) followed by `~` followed by the destructor's class name followed by an empty parameter list is used to declare the destructor in a class definition. In such a declaration, the `~` followed by the destructor's class name can be enclosed in optional parentheses; such parentheses are ignored. A typedef-name shall not be used as the class-name following the `~` in the declarator for a destructor declaration. A declaration of a destructor uses a function declarator (8.3.5 [dcl.fct]) of the form

> ptr-declarator `(` parameter-declaration-clause `)` exception-specificationopt attribute-specifier-seqopt

> where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:

> - in a member-declaration that belongs to the member-specification of a class but is not a friend declaration (11.3 [class.friend]), the id-expression is `~`class-name and the class-name is the injected-class-name (Clause 9 [class]) of the immediately-enclosing class;

> - in a member-declaration that belongs to the member-specification of a class template but is not a friend declaration, the id-expression is `~`class-name and the class-name names the current instantiation (14.6.2.1 [temp.dep.type]) of the immediately-enclosing class template; or

> - in a declaration at namespace scope or in a friend declaration, the id-expression is nested-name-specifier `~`class-name and the class-name names the same class as the nested-name-specifier.

> The class-name shall not be a typedef-name. A destructor shall take no arguments (8.3.5 [dcl.fct]). In a destructor declaration, each decl-specifier of the optional decl-specifier-seq shall be `friend`, `inline`, or `virtual`.

> A destructor is used to destroy objects of its class type. A destructor takes no parameters, and no return type can be specified for it (not even `void`). The address of a destructor shall not be taken. A destructor shall not be `static`. A destructor can be invoked for a `const`, `volatile` or `const volatile` object. A destructor shall not be declared `const`, `volatile` or `const volatile` (9.3.2 [class.this]). `const` and `volatile` semantics (7.1.6.1 [dcl.type.cv]) are not applied on an object under destruction. They stop being in effect when the destructor for the most derived object (1.8 [intro.object]) starts. A destructor shall not be declared with a ref-qualifier.

#### 1510. cv-qualified references via `decltype`

Section: 8.3.2 [dcl.ref] Status: ready Submitter: Richard Smith Date: 2012-06-14

According to 8.3.2 [dcl.ref] paragraph 1,

> Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef (7.1.3 [dcl.typedef]) or of a template type argument (14.3 [temp.arg]), in which case the cv-qualifiers are ignored.

There does not appear to be a good reason not to extend this to apply to apply to `decltype`, as well.

Proposed resolution (October, 2012):

Change 8.3.2 [dcl.ref] paragraph 1 as follows:

> ...Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef typedef-name (7.1.3 [dcl.typedef], 14.1 [temp.param]) or of a template type argument (14.3 [temp.arg]) decltype-specifier (7.1.6.2 [dcl.type.simple]), in which case the cv-qualifiers are ignored. [Example:...

#### 1417. Pointers/references to functions with cv-qualifiers or ref-qualifier

Section: 8.3.5 [dcl.fct] Status: ready Submitter: Daniel Krügler Date: 2011-11-17

It is not sufficiently clear from the existing wording that pointers and references to function types containing cv-qualifiers or a ref-qualifier are not permitted and thus would result in a deduction failure if created during template argument substitution. Normative wording to that effect should be added to, e.g., 8.3.5 [dcl.fct].

Proposed resolution (October, 2012):

1. Change 8.3.1 [dcl.ptr] paragraph 4 as follows:

> [Note: There are no pointers to references Forming a pointer to reference type is ill-formed; see 8.3.2 [dcl.ref]. Forming a pointer to a function type that has cv-qualifiers or a ref-qualifier is ill-formed; see 8.3.5 [dcl.fct]. Since the address of a bit-field (9.6 [class.bit]) cannot be taken, a pointer can never point to a bit-field. —end note]

2. Change 8.3.2 [dcl.ref] paragraph 6 as follows:

> If a typedef typedef-name (7.1.3 [dcl.typedef]), a type template-parameter (14.3.1 [temp.arg.type]), 14.1 [temp.param]) or a decltype-specifier (7.1.6.2 [dcl.type.simple]) denotes a type `TR` that is a reference to a type `T`, an attempt to create...

3. Add the following as a new paragraph at the end of 8.3.2 [dcl.ref]:

> [Note: Forming a reference to a function type that has cv-qualifiers or a ref-qualifier is ill-formed; see 8.3.5 [dcl.fct]. —end note]

4. Change 8.3.5 [dcl.fct] paragraph 6 as follows:

> A function type with a cv-qualifier-seq or a ref-qualifier (including by typedef-name (7.1.3 [dcl.typedef], 14.1 [temp.param]) or decltype-specifier (7.1.6.2 [dcl.type.simple])) shall only be part of appear as:

> - ...

> - the type-id of a template-argument for a type-parameter (14.2 [temp.names] 14.3.1 [temp.arg.type]).

> [Example:

>        typedef int FIC(int) const;
>        FIC f;       // ill-formed: does not declare a member function
>        struct S {
>         FIC f;      // OK
>        };
>        FIC S::*pm = &S::f; // OK

> —end example]

> The effect of a cv-qualifier-seq in a function declarator...

5. Delete the following text from 8.3.5 [dcl.fct] paragraph 10 (the example is moved to paragraph 6, as indicated in the preceding change):

> A typedef of a function type whose declarator includes a cv-qualifier-seq shall be used only to declare the function type for a non-static member function, to declare the function type to which a pointer to member refers, or to declare the top-level function type of another function typedef declaration. [Example: ... —end example]

#### 1502. Value initialization of unions with member initializers

Section: 8.5 [dcl.init] Status: ready Submitter: Richard Smith Date: 2012-05-06

According to 8.5 [dcl.init] paragraph 7,

> To value-initialize an object of type `T` means:

> - if `T` is a (possibly cv-qualified) class type (Clause 9 [class]) with either no default constructor (12.1 [class.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized;

> - if `T` is a (possibly cv-qualified) non-union class type without a user-provided or deleted default constructor, then the object is zero-initialized and, if `T` has a non-trivial default constructor, default-initialized;

> - if `T` is an array type, then each element is value-initialized;

> - otherwise, the object is zero-initialized.

In an example like

      union U { int a = 5; };
      int main() { return U().a; }

this means that the value returned is `0`, because none of the first three bullets apply. Should the “non-union” restriction be dropped from the second bullet?

Proposed resolution (October, 2012):

Change 8.5 [dcl.init] paragraph 7 as follows:

> To value-initialize an object of type `T` means:

> - ...

> - if `T` is a (possibly cv-qualified) non-union class type without a user-provided or deleted default constructor, then the object is zero-initialized and, if `T` has a non-trivial default constructor, default-initialized;

> - ...

#### 1328. Conflict in reference binding vs overload resolution

Section: 8.5.3 [dcl.init.ref] Status: ready Submitter: Johannes Schaub Date: 2011-05-31

According to 13.3.1.6 [over.match.ref] paragraph 1, the determination of the candidate functions is based on whether 8.5.3 [dcl.init.ref] requires an lvalue result or an rvalue result. It is not sufficiently clear exactly what this means, particularly with respect to function lvalues and rvalues.

Proposed resolution (August, 2011):

1. Change 13.3.1.6 [over.match.ref] paragraph 1 as follows:

- The conversion functions of `S` and its base classes are considered, except that for copy-initialization, only the non-explicit conversion functions are considered. Those that are not hidden within `S` and yield type “lvalue reference to cv2 `T2`” (when 8.5.3 [dcl.init.ref] requires an lvalue result initializing an lvalue reference or an rvalue reference to function) or “cv2 `T2`” or “rvalue reference to cv2 `T2`” (when 8.5.3 [dcl.init.ref] requires an rvalue result initializing an rvalue reference or an lvalue reference to function), where “cv1 `T`” is reference-compatible (8.5.3 [dcl.init.ref]) with “cv2 `T2`”, are candidate functions.

2. Change 13.3.3 [over.match.best] paragraph 1 as follows:

- ...

- the context is an initialization by user-defined conversion... or if not that,

- the context is an initialization by conversion function for direct reference binding (13.3.1.6 [over.match.ref]) of a reference to function type, the return type of `F1` is the same kind of reference (i.e. lvalue or rvalue) as the reference being initialized, and the return type of `F2` is not [Example:

        template <class T> struct A {
          operator T&();  // #1
          operator T&&(); // #2
        };
        typedef int Fn();
        A<Fn> a;
        Fn& lf = a;      // calls #1
        Fn&& rf = a;     // calls #2

  —end example] or, if not that,

- `F1` is a non-template function...

#### 1506. Value category of `initializer_list` object

Section: 8.5.4 [dcl.init.list] Status: ready Submitter: Steve Adamczyk Date: 2012-05-29

One of the bullets in 8.5.4 [dcl.init.list] paragraph 3 says,

> Otherwise, if `T` is a specialization of `std::initializer_list<E>,` an `initializer_list` object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5 [dcl.init]).

This does not, but should, say whether the `initializer_list` object is treated as an lvalue or prvalue for the purpose of the 8.5 [dcl.init] initialization.

Proposed resolution (October, 2012):

Change 8.5.4 [dcl.init.list] paragraph 3 as follows:

> List-initialization of an object or reference of type `T` is defined as follows:

> - ...

> - Otherwise, if `T` is a specialization of `std::initializer_list<E>`, an a prvalue `initializer_list` object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5 [dcl.init]).

> - ...

#### 1522. Access checking for `initializer_list` array initialization

Section: 8.5.4 [dcl.init.list] Status: ready Submitter: John Spicer Date: 2012-07-12

In constructing an `initializer_list` object from an initializer list, 8.5.4 [dcl.init.list] paragraph 5 says of the underlying array,

> Each element of that array is copy-initialized with the corresponding element of the initializer list

It would probably be good to mention that the copy/move constructor for this copy must be accessible in the context in which the initialization occurs.

Proposed resolution (October, 2012):

Change 8.5.4 [dcl.init.list] paragraph 4 as follows:

> ...Each element of that array is copy-initialized with the corresponding element of the initializer list, and the `std::initializer_list<E>` object is constructed to refer to that array. [Note: A constructor or conversion function selected for the copy shall be accessible (Clause 11 [class.access]) in the context of the initializer list. —end note] If a narrowing conversion is required...

#### 1318. Syntactic ambiguities with `final`

Section: 9 [class] Status: ready Submitter: Johannes Schaub Date: 2011-05-14

The ambiguity in an example like

      struct A final { };

is resolved by 2.11 [lex.name] paragraph 2 to be the declaration of a variable named `final`:

> any ambiguity as to whether a given identifier has a special meaning is resolved to interpret the token as a regular identifier.

Similarly, in an example like

      struct C { constexpr operator int() { return 5; } };
      struct A {
       struct B final : C{};
      };

`final` is taken as the name of a bit-field member rather than as the name of a nested class.

Proposed resolution (October, 2012):

1. Change 2.11 [lex.name] paragraph 2 as follows:

> The identifiers in Table 3 have a special meaning when appearing in a certain context. When referred to in the grammar, these identifiers are used explicitly rather than using the identifier grammar production. Unless otherwise specified, any ambiguity as to whether a given identifier has a special meaning is resolved to interpret the token as a regular identifier.

2. Change 9 [class] paragraph 3 as follows:

> If a class is marked with the class-virt-specifier `final` and it appears as a base-type-specifier in a base-clause (Clause 10 [class.derived]), the program is ill-formed. Whenever a class-key is followed by a class-head-name, the identifier `final`, and a colon or left brace, `final` is interpreted as a class-virt-specifier. [Example:

>       struct A;
>       struct A final {};      // OK: definition of struct A,
>                               // not value-initialization of variable final

>       struct X {
>        struct C { constexpr operator int() { return 5; } };
>        struct B final : C{};  // OK: definition of nested class B,
>                               // not declaration of a bit-field member final
>       };

> —end example]

#### 1411. More on global scope `::` in nested-name-specifier

Section: 9 [class] Status: ready Submitter: David Blaikie Date: 2011-10-28

The resolution of issue 355 failed to update the grammar for class-head-name in 9 [class] paragraph 1 and removed the optional `::` from class-or-decltype in 10 [class.derived] paragraph 1, with the result that it is still not possible to globally-qualify a class name in a class definition, and the ability to globally-qualify a base class name has been lost.

Proposed resolution (February, 2012):

Change the grammar in 5.1.1 [expr.prim.general] paragraph 8 as follows:

qualified-id:

nested-name-specifier `template` opt unqualified-id
`::` identifier
`::` operator-function-id
`::` literal-operator-id
`::` template-id

nested-name-specifier:

`::`
`::`opt type-name `::`
`::`opt namespace-name `::`
decltype-specifier `::`
nested-name-specifier identifier `::`
nested-name-specifier `template` opt simple-template-id `::`

#### 1425. Base-class subobjects of standard-layout structs

Section: 9.2 [class.mem] Status: ready Submitter: Ville Voutilainen Date: 2011-12-07

According to 9.2 [class.mem] paragraph 20,

> A pointer to a standard-layout struct object, suitably converted using a `reinterpret_cast`, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

Given a standard-layout struct in which the non-static data members are in a base class (and hence the derived class is empty), it is not clear what the “initial member” is. Presumably the intent behind allowing such standard-layout classes was to treat the base class object and its first non-static data member as the initial member of the derived class, but this does not appear to be spelled out anywhere.

Proposed resolution (February, 2012):

Change 9.2 [class.mem] paragraph 20 as follows:

> A pointer to a standard-layout struct object, suitably converted using a `reinterpret_cast`, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any). [Note:...

#### 1556. Constructors and explicit conversion functions in direct initialization

Section: 13.3.1.4 [over.match.copy] Status: ready Submitter: Edward Catmur Date: 2012-09-18

Issue 899 added wording to the second bullet of 13.3.1.4 [over.match.copy] paragraph 1 permitting use of `explicit` conversion functions when calling a copy constructor in a direct-initialization context. Issue 1087 addressed the problem in the earlier resolution that the phrase “copy constructor” did not include move constructors and template constructors. However, the term “copy constructor” implicitly (and correctly) restricted the constructor parameter to be the constructor's class, i.e., the class of the object being directly initialized. The new phrasing, “a constructor that takes a reference to possibly cv-qualified `T` as its first argument,” incorrectly assumed that `T` referred to the type of the object being initialized; however, that is not the case, and a converting constructor from `T` to the type of the object being initialized is inadvertently permitted. The wording needs a further tweak to restore the intended context.

Proposed resolution (October, 2012):

Change the second bullet of 13.3.1.4 [over.match.copy] paragraph 1 as follows:

> ...Assuming that “cv1 `T`” is the type of the object being initialized, with `T` a class type, the candidate functions are selected as follows:

> - The converting constructors (12.3.1 [class.conv.ctor]) of `T` are candidate functions.

> - When the type of the initializer expression is a class type “cv `S`”, the non-explicit conversion functions of `S` and its base classes are considered. When initializing a temporary to be bound to the first parameter of a constructor that takes a reference to possibly cv-qualified `T` as its first argument, called with a single argument in the context of direct-initialization of an object of type “cv2 `T`”, explicit conversion functions are also considered. Those that are not hidden within `S` and yield a type whose cv-unqualified version is the same type as `T` or is a derived class thereof are candidate functions. Conversion functions that return “reference to `X`” return lvalues or xvalues, depending on the type of reference, of type `X` and are therefore considered to yield `X` for this process of selecting candidate functions.

#### 1543. Implicit conversion sequence for empty initializer list

Section: 13.3.3.1.5 [over.ics.list] Status: ready Submitter: Steve Adamczyk Date: 2012-08-21

According to 13.3.3.1.5 [over.ics.list] paragraph 6, when passing an initializer-list argument to a non-class parameter,

> if the initializer list has no elements, the implicit conversion sequence is the identity conversion.

However, there is no similar provision for an empty initializer list passed to a specialization of `std::initializer_list` or an array, as described in paragraph 2:

> If the parameter type is `std::initializer_list<X>` or “array of `X`”134 and all the elements of the initializer list can be implicitly converted to `X`, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to `X`.

It is not clear what the result should be for a list with no elements. For example, given

      void f(int) { printf("int\n"); }
      void f(std::initializer_list<int>) { printf("init list\n"); }
      int main() {
          f({});
      }

current implementations result in `init list` being printed, presumably on the basis of the last bullet of 13.3.3.2 [over.ics.rank] paragraph 3:

- List-initialization sequence `L1` is a better conversion sequence than list-initialization sequence `L2` if `L1` converts to `std::initializer_list<X>` for some `X`\and `L2` does not.

That would imply that both conversion sequences are the identity conversion, which is reasonable, but it should be stated clearly if that is the intent.

Proposed resolution (October, 2012):

Change 13.3.3.1.5 [over.ics.list] paragraph 2 as follows:

> If the parameter type is `std::initializer_list<X>` or “array of `X`”134 and all the elements of the initializer list can be implicitly converted to `X`, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to `X`, or if the initializer list has no elements, the identity conversion. This conversion can be a user-defined conversion even in the context of a call to an initializer-list constructor. [Example:

>       void f(std::initializer_list<int>);
>       f( {} );        // OK: f(initializer_list) identity conversion
>       f( {1,2,3} );   // OK: f(initializer_list<int>) identity conversion
>       f( {'a','b'} ); // OK: f(initializer_list<int>) integral promotion
>       f( {1.0} );     // error: narrowing
>       ...

#### 1374. Qualification conversion vs difference in reference binding

Section: 13.3.3.2 [over.ics.rank] Status: ready Submitter: Michael Wong Date: 2011-08-15

The rule in 13.3.3.2 [over.ics.rank] paragraph 3 for ranking based on a difference in qualification conversion applies only if they "differ only in their qualification conversion".

It is unclear as to whether the property of being a reference binding is a factor in determining if there is a difference between conversion sequences. Notice that 13.3.3.1.4 [over.ics.ref] maps reference bindings to other forms of implicit conversion sequences, but does not state that the property of being a reference binding is preserved; however, 13.3.3.2 [over.ics.rank] has cases which depend on whether certain standard conversion sequences are reference bindings or not and on the specifics of the bindings.

In the following, picking `T2 &&` would bind an rvalue to an rvalue reference. Picking `T1 &` would bind an rvalue to an lvalue reference, but the qualification conversion to `T1` is "better". Which is better?

        typedef int *      *      *const *const T1;
        typedef int *const *const *const *const T2;
        void foo(T1 &);
        void foo(T2 &&) { }

        int main() {
           foo((int ****)0);
           return 0;
        }

Notes from the February, 2012 meeting:

The CWG agreed that bullets 3 and 4 should be reversed, to check the reference binding first and then for qualification conversion.

Proposed resolution (February, 2012):

Move 13.3.3.2 [over.ics.rank] paragraph 3, first bullet, third sub-bullet, after the current fifth sub-bullet, as follows:

> Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

> - Standard conversion sequence `S1` is a better conversion sequence...

> - `S1` is a proper subsequence of `S2`...

> - the rank of `S1` is better...

> - `S1` and `S2` differ only in their qualification conversion... —end example] or if not that,

> - `S1` and `S2` are reference bindings (8.5.3 [dcl.init.ref]) and neither refers... or if not that,

> - `S1` and `S2` are reference bindings (8.5.3 [dcl.init.ref]) and S1 binds... —end example] or, if not that,

> - `S1` and `S2` differ only in their qualification conversion... —end example] or if not that,

> - User-defined conversion sequence `U1`...

#### 1481. Increment/decrement operators with reference parameters

Section: 13.5.7 [over.inc] Status: ready Submitter: Ryou Ezoe Date: 2012-03-20

The phrase in 13.5.7 [over.inc] paragraph 1,

> a non-member function with one parameter of class or enumeration type

inadvertently excludes reference parameters, and in fact, no mention of the type is necessary in light of 13.5 [over.oper] paragraph 6:

> An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.

Proposed resolution (August, 2012):

Change 13.5.7 [over.inc] paragraph 1 as follows:

> The user-defined function called `operator++` implements the prefix and postfix `++` operator. If this function is a member function with no parameters, or a non-member function with one parameter of class or enumeration type, it defines the prefix increment operator ++ for objects of that type. If the function...

#### 1479. Literal operators and default arguments

Section: 13.5.8 [over.literal] Status: ready Submitter: Jason Merrill Date: 2012-03-13

It appears that an example like

      int operator"" _a (const char *, std::size_t = 0);
      int operator"" _a (const char *);

      int i = 123_a;

is ambiguous: although only the second declaration is a raw literal operator, the corresponding call

      operator"" _a ("123")

could match either declaration. Should default arguments for literal operators be prohibited?

Proposed resolution (October, 2012):

Change 13.5.8 [over.literal] paragraph 3 as follows:

> The declaration of a literal operator shall have a parameter-declaration-clause equivalent to one of the following:

> ...

> If a parameter has a default argument (8.3.6 [dcl.fct.default]), the program is ill-formed.

#### 1533. Function pack expansion for member initialization

Section: 14.5.3 [temp.variadic] Status: ready Submitter: Jonathan Caves Date: 2012-08-06

The list of pack expansion contexts in 14.5.3 [temp.variadic] paragraph 4 includes a mem-initializer-list, with no restriction on whether the mem-initializer corresponds to a base class or a member. However, it appears from 12.6.2 [class.base.init] paragraph 15 that such a pack expansion is intended for bases:

> A mem-initializer followed by an ellipsis is a pack expansion (14.5.3 [temp.variadic]) that initializes the base classes specified by a pack expansion in the base-specifier-list for the class.

This is not conclusive, however, and use of a pack expansion with a mem-initializer for a member could be used with packs containing zero or one element:

      class S { };

      template<typename... T> class X {
      public:
        X(T ...args) : data_(args)... { }
      private:
        S data_;
      };

      int main() {
        S s;
        X<> x1;
        X<S> x2(s);
      }

The Standard should be clarified as to whether such a usage is permitted or not.

Proposed resolution (October, 2012):

Change 14.5.3 [temp.variadic] paragraph 4 as follows:

> ...Pack expansions can occur in the following contexts:

> - ...

> - In a mem-initializer-list (12.6.2 [class.base.init]) for a mem-initializer whose mem-initializer-id denotes a base class; the pattern is a the mem-initializer.

> - ...

#### 1495. Partial specialization of variadic class template

Section: 14.5.5 [temp.class.spec] Status: ready Submitter: Jason Merrill Date: 2012-04-16

Consider an example like

      template <int B, typename Type1, typename... Types>
      struct A;

      template<typename... Types>
      struct A<0, Types...> { };

      A<0,int,int> t;

In this case, the partial specialization seems well-formed by the rules in 14.5.5 [temp.class.spec], but it is not more specialized than the primary template. However, 14.5.5.1 [temp.class.spec.match] says that if exactly one matching specialization is found, it is used, which suggests that the testcase is well-formed. That seems undesirable; I think a partial specialization that is not more specialized than the primary template should be ill-formed.

If the example is rewritten so that both versions are partial specializations, i.e.,

      template <int B, typename... Types>
      struct A;

      template <int B, typename Type1, typename... Types>
      struct A<B, Type1, Types...> { }

      template<typename... Types>
      struct A<0, Types...> { };

      A<0,int,int> t;

There is implementation variance, with gcc and clang reporting an ambiguity and EDG choosing the second specialization.

Proposed resolution (October, 2012):

Add the following as a new bullet in 14.5.5 [temp.class.spec] paragraph 8:

- ...

- The argument list of the specialization shall not be identical to the implicit argument list of the primary template.

- The specialization shall be more specialized than the primary template (14.5.5.2 [temp.class.order]).

- ...

#### 903. Value-dependent integral null pointer constants

Section: 14.6.2.3 [temp.dep.constexpr] Status: ready Submitter: Doug Gregor Date: 22 May, 2009

Consider the following example:

        void f(int*);
        void f(...);

        template <int N> void g() {
          f(N);
        }

        int main() {
          g<0>();
          g<1>();
        }

The call to `f` in `g` is not type-dependent, so the overload resolution must be done at definition time rather than at instantiation time. As a result, both of the calls to `g` will result in calls to `f(...)`, i.e., `N` will not be a null pointer constant, even if the value of `N` is 0.

It would be most consistent to adopt a rule that a value-dependent expression can never be a null pointer constant, even in cases like

        template <int N> void g() {
          int* p = N;
        }

This would always be ill-formed, even when `N` is 0.

John Spicer: It's clear that this treatment is required for overload resolution, but it seems too expansive given that there are other cases in which the value of a template parameter can affect the validity of the program, and an implementation is forbidden to issue a diagnostic on a template definition unless there are no possible valid specializations.

Notes from the July, 2009 meeting:

There was a strong consensus among the CWG that only the literal `0` should be considered a null pointer constant, not any arbitrary zero-valued constant expression as is currently specified.

Proposed resolution (October, 2012):

1. Change 4.10 [conv.ptr] paragraph 1 as follows:

> A null pointer constant is an integral constant expression (5.19 [expr.const]) prvalue of integer type that evaluates to integer literal (2.14.2 [lex.icon]) with value zero or a prvalue of type `std::nullptr_t`. A null pointer constant can be converted...

2. Change 5.19 [expr.const] paragraph 3 as follows:

> ...[Note: Such expressions may be used as array bounds (8.3.4 [dcl.array], 5.3.4 [expr.new]), as bit-field lengths (9.6 [class.bit]), as enumerator initializers if the underlying type is not fixed (7.2 [dcl.enum]), as null pointer constants (4.10 [conv.ptr]), and as alignments (7.6.2 [dcl.align]). —end note]...

3. Change 8.5 [dcl.init] paragraph 5 as follows:

> To zero-initialize an object or reference of type `T` means:

> - if `T` is a scalar type (3.9 [basic.types]), the object is set to the value `0` (zero), taken as an integral constant expression, converted initialized to the value obtained by converting integer literal `0` (zero) to `T`; [Footnote: As specified in 4.10 [conv.ptr], converting an integral constant expression integer literal whose value is 0 to a pointer type results in a null pointer value. —end footnote]

> - ...

4. Change 14.3.2 [temp.arg.nontype] paragraph 5 as follows:

- ...

- for a non-type template-parameter of type pointer to object, qualification conversions (4.4 [conv.qual]) and the array-to-pointer conversion (4.2 [conv.array]) are applied; if the template-argument is of type `std::nullptr_t`, the null pointer conversion (4.10 [conv.ptr]) is applied. [Note: In particular, neither the null pointer conversion for a zero-valued integral constant expression integer literal (4.10 [conv.ptr]) nor the derived-to-base conversion (4.10 [conv.ptr]) are applied. Although 0 is...

- ...

5. Change 15.3 [except.handle] paragraph 3 as follows:

> ...[Note: A throw-expression whose operand is an integral constant expression of integer type that evaluates to integer literal with value zero does not match a handler of pointer or pointer to member type. —end note]. [Example: ...

6. Add a new section to C.2 [diff.cpp03] as follows:

> C.2.x Clause 4: standard conversions | [diff.cpp03.conv]

> 4.10 [conv.ptr]
> Change: Only literals are integer null pointer constants
> Rationale: Removing surprising interactions with templates and constant expressions
> Effect on original feature: Valid C++ 2003 code may fail to compile or produce different results in this International Standard, as the following example illustrates:

>       void f(void *);  // #1
>       void f(...);     // #2
>       template<int N> void g() {
>           f(0*N);      // calls #2; used to call #1
>       }

#### 1413. Missing cases of value-dependency

Section: 14.6.2.3 [temp.dep.constexpr] Status: ready Submitter: Richard Smith Date: 2011-11-09

The list of cases in 14.6.2.3 [temp.dep.constexpr] paragraph 2 in which an identifier is value-dependent should also include:

- an entity with reference type and is initialized with an expression that is value-dependent

- a member function or a static data member of the current instantiation

Proposed resolution (October, 2012):

1. Change 14.6.2.3 [temp.dep.constexpr] paragraph 2 as follows and move the text following the bulleted list into a new paragraph:

> An identifier id-expression is value-dependent if it is:

> - it is a name declared with a dependent type,

> - it is the name of a non-type template parameter,

> - it names a member of an unknown specialization,

> - it names a static data member of the current instantiation that is not initialized in a member-declarator,

> - it names a static member function that is a member of the current instantiation, or

> - it is a constant with literal type and is initialized with an expression that is value-dependent.

> Expressions of the following form...

2. Change 14.6.2.3 [temp.dep.constexpr] paragraph 5 as follows:

> An id-expression is value-dependent if it names a member of an unknown specialization. An expression of the form `&`qualified-id where the qualified-id's nested-name-specifier names the current instantiation is value-dependent.

#### 1532. Explicit instantiation and member templates

Section: 14.7.2 [temp.explicit] Status: ready Submitter: Johannes Schaub Date: 2012-08-04

According to 14.7.2 [temp.explicit] paragraph 8,

> An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below.

This could be read as an indication that member class templates and member function templates are instantiated (as templates) when their containing class template is instantiated. For example,

      template<typename T> struct A {
        template<typename U> void f() {
          T t;
          t.f();
        }
      };

      template struct A<int>;

In this view, the result would be a member function template definition in class `A<int>` equivalent to

      template<typename U> void f() {
        int t;
        t.f();
      }

Such a template could never be validly instantiated and thus would presumably fall under the rule in 14.6 [temp.res] paragraph 8,

> If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.

The wording of 14.7.2 [temp.explicit] paragraph 1 appears not to allow member templates to be instantiated as templates, however, mentioning only a “member template specialization” as a possibility:

> A class, a function or member template specialization can be explicitly instantiated from its template. A member function, member class or static data member of a class template can be explicitly instantiated from the member definition associated with its class template.

This appears to be a contradiction, and although a diagnostic for a member template such as the example above would be helpful, most or all current implementations do not do so. Either the wording of paragraph 1 should be changed to allow explicit instantiation of a member template as a template, analogous to explicitly specializing a member template as a template, or paragraph 8 should be clarified to exclude member templates from the members explicitly instantiated when the containing class template is explicitly instantiated.

Proposed resolution (October, 2012):

Change 14.7.2 [temp.explicit] paragraph 8 as follows:

> An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes and members that are templates) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below. [Note: In addition, it will typically be an explicit instantiation of certain implementation-dependent data about the class. —end note]

#### 1330. Delayed instantiation of `noexcept` specifiers

Section: 14.8.2 [temp.deduct] Status: ready Submitter: Jason Merrill Date: 2011-06-05

See also issues 595 and 287.

The use of `noexcept` specifiers can cause instantiation of classes and functions that are not actually needed in the program, just to be able to complete the declaration. The actual value of the expression in the noexcept-specification is only needed if the function is defined (i.e., instantiated) or called, so it would significantly reduce the number of instantiations (and avoid certain kinds of errors when the value is currently required before a class is complete) if exception-specifications were treated like default arguments and only instantiated when they are actually needed.

Proposed resolution (February, 2012):

1. Change 14.5 [temp.decls] paragraph 2 as follows:

> For purposes of name lookup and instantiation, default arguments and exception-specifications of function templates and default arguments and exception-specifications of member functions of class templates are considered definitions; each default argument or exception-specification is a separate definition which is unrelated to the function template definition or to any other default arguments or exception-specifications.

2. Change 14.6 [temp.res] paragraph 11 as follows:

> [Note: For purposes of name lookup, default arguments and exception-specifications of function templates and default arguments and exception-specifications of member functions of class templates are considered definitions (14.5). —end note]

3. Add a new paragraph following 14.6.4.1 [temp.point] paragraph 2:

> If a function template or member function of a class template is called in a way which uses the definition of a default argument of that function template or member function, the point of instantiation of the default argument is the point of instantiation of the function template or member function specialization.

> For an exception-specification of a function template specialization or specialization of a member function of a class template, if the exception-specification is implicitly instantiated because it is needed by another template specialization and the context that requires it depends on a template parameter, the point of instantiation of the exception-specification is the point of instantiation of the specialization that requires it. Otherwise, the point of instantiation for such an exception-specification immediately follows the namespace scope declaration or definition that requires the exception-specification.

4. Change 14.7.1 [temp.inst] paragraph 1 as follows:

> ...The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, or default arguments, or exception-specifications, of the class member functions, member classes...

5. Add a new paragraph following 14.7.1 [temp.inst] paragraph 13:

> Each default argument is instantiated independently. [Example: ... —end example]

> If the exception-specification of a specialization of a function template or member function of a class template has not yet been instantiated, but is needed (e.g., to instantiate the function definition, to evaluate a noexcept-expression (5.3.7 [expr.unary.noexcept]), or to compare against the exception-specification of another declaration), the dependent names are looked up, the semantic constraints are checked, and the instantiation of any template used in the exception-specification is done as if it were being done as part of instantiating the declaration of the specialization. An exception-specification is not instantiated in order to calculate the exception-specification of a defaulted function in a derived class until the exception-specification of the derived member function becomes necessary.

6. Change the note 14.8.2 [temp.deduct] paragraph 7 as follows:

> ...[Note: The equivalent substitution in exception specifications is done only when the function exception-specification is instantiated, at which point a program is ill-formed if the substitution results in an invalid type or expression. —end note]

7. Add a new paragraph following 15.4 [except.spec] paragraph 15:

> A deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]) with no explicit exception-specification is treated as if it were specified with `noexcept(true)`.

> The exception-specification of a function template specialization is not instantiated along with the function declaration; it is instantiated when needed (14.7.1 [temp.inst]). The exception-specification of an implicitly-declared special member function is also evaluated as needed. [Note: Therefore, an implicit declaration of a member function of a derived class does not require the exception-specification of a base member function to be instantiated. —end note]

Notes from the February, 2012 meeting:

There should be a specific definition of when an exception-specification is needed and must thus be instantiated.

Additional discussion (September, 2012):

Daveed Vandevoorde brought up two additional points. First, the rule should be crafted so that an example like the following is ill-formed:

      template<class T> T f() noexcept(sizeof(T) < 4);

      int main() {
        decltype(f<void>()) *p;
      }

Even though the exception-specification is not needed here, it should be instantiated (because of the unevaluated reference to `f`) in order to catch the ill-formed `sizeof(T)`.

In addition, the proposed change creates an asymmetry between class templates and ordinary classes:

      struct S {
        void f() noexcept(sizeof(g()) < 8); // Invalid forward reference.
        static int g();
      };

but

      template<typename> struct X {
          void f() noexcept(sizeof(g()) < 8); // Okay.
          static int g();
      };

If the proposed change is adopted, the rules for exception-specifications in ordinary classes should be revised to make the parallel usage well-formed.

Proposed resolution (October, 2012):

1. Change 3.3.7 [basic.scope.class] paragraph 1 #1 as follows:

> The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).

2. Change 3.4.1 [basic.lookup.unqual] paragraph 7 as follows:

> A name used in the definition of a class `X` outside of a member function body, default argument, exception-specification, brace-or-equal-initializer of a non-static data member, or nested class definition29 shall be declared in one of the following ways:...

3. Change 3.4.1 [basic.lookup.unqual] paragraph 8 as follows:

> For the members of a class `X`, a name used in a member function body, in a default argument, in an exception-specification, in the brace-or-equal-initializer of a non-static data member (9.2 [class.mem]), or in the definition of a class member outside of the definition of `X`, following the member's declarator-id31 , shall be declared in one of the following ways:...

4. Change 9.2 [class.mem] paragraph 2 as follows:

> A class is considered a completely-defined object type (3.9 [basic.types]) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

5. Change 14.5 [temp.decls] paragraph 2 as follows:

> For purposes of name lookup and instantiation, default arguments and exception-specifications of function templates and default arguments and exception-specifications of member functions of class templates are considered definitions; each default argument or exception-specification is a separate definition which is unrelated to the function template definition or to any other default arguments or exception-specifications.

6. Change 14.6 [temp.res] paragraph 11 as follows:

> [Note: For purposes of name lookup, default arguments and exception-specifications of function templates and default arguments and exception-specifications of member functions of class templates are considered definitions (14.5 [temp.decls]). —end note]

7. Add the following as a new paragraph after 14.6.4.1 [temp.point] paragraph 2:

> If a function template or member function of a class template is called in a way which uses the definition of a default argument of that function template or member function, the point of instantiation of the default argument is the point of instantiation of the function template or member function specialization.

> For an exception-specification of a function template specialization or specialization of a member function of a class template, if the exception-specification is implicitly instantiated because it is needed by another template specialization and the context that requires it depends on a template parameter, the point of instantiation of the exception-specification is the point of instantiation of the specialization that requires it. Otherwise, the point of instantiation for such an exception-specification immediately follows the namespace scope declaration or definition that requires the exception-specification.

8. Change 14.7.1 [temp.inst] paragraph 1 as follows:

> Unless a class template specialization has been explicitly instantiated (14.7.2 [temp.explicit]) or explicitly specialized (14.7.3 [temp.expl.spec]), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, or default arguments, or exception-specifications of the class member functions, member classes, scoped member enumerations, static data members and member templates; and it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions. However, for the purpose...

9. Insert the following as a new paragraph immediately preceding 14.7.1 [temp.inst] paragraph 14:

> The exception-specification of a function template specialization is not instantiated along with the function declaration; it is instantiated when needed (15.4 [except.spec]). If such an exception-specification is needed but has not yet been instantiated, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the exception-specification is done as if it were being done as part of instantiating the declaration of the specialization at that point.

> [Note: 14.6.4.1 [temp.point] defines the point of instantiation of a template specialization. —end note]

10. Change 14.8.2 [temp.deduct] paragraph 7 as follows:

> The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions. [Note: The equivalent substitution in exception specifications is done only when the function exception-specification is instantiated, at which point a program is ill-formed if the substitution results in an invalid type or expression. —end note]

11. Change 15.4 [except.spec] paragraph 2 as follows:

> ...A type denoted in an exception-specification shall not denote an incomplete type other than a class currently being defined. A type denoted in an exception-specification shall not denote a pointer or reference to an incomplete type, other than cv `void*` or a pointer or reference to a class currently being defined. A type cv `T`, “array of `T`”, or “function returning `T`” denoted in an exception-specification is adjusted to type `T`, “pointer to `T`”, or “pointer to function returning `T`” respectively.

12. Add the following as a new paragraph following 15.4 [except.spec] paragraph 15:

> A deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]) with no explicit exception-specification is treated as if it were specified with `noexcept(true)`.

> An exception-specification is considered to be needed when:

> - in an expression, the function is the unique lookup result or the selected member of a set of overloaded functions (3.4 [basic.lookup], 13.3 [over.match], 13.4 [over.over]);

> - the function is odr-used (3.2 [basic.def.odr]) or, if it appears in an unevaluated operand, would be odr-used if the expression were potentially-evaluated;

> - the exception-specification is compared to that of another declaration (e.g. an explicit specialization or an overriding virtual function);

> - the function is defined; or

> - the exception-specification is needed for a defaulted special member function that calls the function. [Note: A defaulted declaration does not require the exception-specification of a base member function to be evaluated until the implicit exception-specification of the derived function is needed, but an explicit exception-specification needs the implicit exception-specification to compare against. —end note]

> The exception-specification of a defaulted special member function is evaluated as described above only when needed; similarly, the exception-specification of a specialization of a function template or member function of a class template is instantiated only when needed.

[Note: this resolution reverses the decision in issue 1308.]

#### 1503. Exceptions during copy to exception object

Section: 15.1 [except.throw] Status: ready Submitter: Daniel Krügler Date: 2012-05-11

According to 15.1 [except.throw] paragraph 7,

> If the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught, calls a function that exits via an exception, `std::terminate` is called (15.5.1 [except.terminate]).

This wording was overlooked in the resolution for issue 475 and should be changed, along with the following example, to indicate that `std::terminate` will be called for an uncaught exception only after initialization of the exception object is complete.

Proposed resolution (August, 2012):

Change 15.1 [except.throw] paragraph 7 as follows:

> If the exception handling mechanism, after completing evaluation of the expression to be thrown the initialization of the exception object but before the exception is caught activation of a handler for the exception, calls a function that exits via an exception, `std::terminate` is called (15.5.1 [except.terminate]). [Example:

>       struct C {
>         C() { }
>         C(const C&) { throw 0; }
>           if (std::uncaught_exception()) {
>             throw 0;    // throw during copy to handler's exception-declaration object (15.3 [except.handle])
>           }
>         }
>       };

>       int main() {
>         try {
>           throw C();   // calls std::terminate() if construction of the handler's
>                        // exception-declaration object is not elided (12.8 [class.copy])
>         } catch(C) { }
>       }

> —end example]

#### 223. The meaning of deprecation

Section: D [depr] Status: ready Submitter: Mike Miller Date: 19 Apr 2000

During the discussion of issues 167 and 174, it became apparent that there was no consensus on the meaning of deprecation. Some thought that deprecating a feature reflected an intent to remove it from the language. Others viewed it more as an encouragement to programmers not to use certain constructs, even though they might be supported in perpetuity.

There is a formal-sounding definition of deprecation in Annex D [depr] paragraph 2:

> deprecated is defined as: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in future revisions.

However, this definition would appear to say that any non-deprecated feature is "guaranteed to be part of the Standard in future revisions." It's not clear that that implication was intended, so this definition may need to be amended.

This issue is intended to provide an avenue for discussing and resolving those questions, after which the original issues may be reopened if that is deemed desirable.

Proposed resolution (August, 2012):

Change D [depr] paragraph 2 as follows:

> These are deprecated features, where deprecated is defined as: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in having been identified as a candidate for removal from future revisions.

### Issues with "Tentatively Ready" Status

#### 1465. `noexcept` and `std::bad_array_new_length`

Section: 5.3.7 [expr.unary.noexcept] Status: tentatively ready Submitter: Daniel Krügler Date: 2012-02-12

The list of causes for a `false` result of the `noexcept` operator does not include a new-expression with a non-constant array bound, which could result in an exception even if the allocation function that would be called is declared not to throw (see 5.3.4 [expr.new] paragraph 7).

Proposed resolution (October, 2012):

This issue is resolved by the resolution of issue 1351.

#### 1477. Definition of a `friend` outside its namespace

Section: 7.3.1.2 [namespace.memdef] Status: tentatively ready Submitter: John Spicer Date: 2012-03-09

According to 7.3.1.2 [namespace.memdef] paragraph 3,

> Every name first declared in a namespace is a member of that namespace. If a `friend` declaration in a non-local class first declares a class or function95 the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1 [basic.lookup.unqual]) or by qualified lookup (3.4.3 [basic.lookup.qual]) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship).

Taken literally, that would mean the following example is ill-formed:

      namespace N {
        struct A {
          friend int f();
        };
      }
      int N::f() { return 0; }
      int i = N::f();    // ill-formed: N::f not found

because the definition of `N::f` appears in global scope rather than in namespace scope.

Proposed resolution (October, 2012):

Change 7.3.1.2 [namespace.memdef] paragraph 3 as follows:

> Every name first declared in a namespace is a member of that namespace. If a `friend` declaration in a non-local class first declares a class or function95 the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by The `friend` declaration does not by itself make the name visible to unqualified lookup (3.4.1 [basic.lookup.unqual]) or by qualified lookup (3.4.3 [basic.lookup.qual]). [Note: The name of the friend will be visible in its namespace if until a matching declaration is provided in that at namespace scope (either before or after the class definition granting friendship). —end note] If a friend function is called...

#### 1552. exception-specifications and defaulted special member functions

Section: 8.4.2 [dcl.fct.def.default] Status: tentatively ready Submitter: Daveed Vandevoorde Date: 2012-09-07

The current wording of 8.4.2 [dcl.fct.def.default] paragraph 2 has some surprising implications:

> An explicitly-defaulted function may be declared `constexpr` only if it would have been implicitly declared as `constexpr`, and may have an explicit exception-specification only if it is compatible (15.4 [except.spec]) with the exception-specification on the implicit declaration.

In an example like

      struct A {
        A& operator=(A&);
      };
      A& A::operator=(A&) = default;

presumably the exception-specification of `A::operator=(A&)` is `noexcept(false)`. However, attempting to make that exception-specification explicit,

      A& A::operator=(A&) noexcept(false) = default;

is an error. Is this intentional?

Proposed resolution (October, 2012):

Change 15.4 [except.spec] paragraph 4 as follows:

> ...If any declaration of a pointer to function, reference to function, or pointer to member function has an exception-specification, all occurrences of that declaration shall have a compatible exception-specification. If a declaration of a function has an implicit exception-specification, other declarations of the function shall not specify an exception-specification. In an explicit instantiation...

(This resolution also resolves issue 1492.)

#### 1508. Template initializer-list constructors

Section: 8.5.4 [dcl.init.list] Status: tentatively ready Submitter: Daveed Vandevoorde Date: 2012-06-06

Can a constructor template ever be an initializer-list constructor without `std::initializer_list` (or an alias template specialization for it) appearing in the template signature? E.g., is there any way that the constructor in:

      struct S {
        template<typename T> S(T);
      };

can be an initializer-list constructor?

Proposed resolution (October, 2012):

Modify 8.5.4 [dcl.init.list] paragraph 2 as follows:

> A constructor is an initializer-list constructor if its first parameter is of type `std::initializer_list<E>` or reference to possibly cv-qualified `std::initializer_list<E>` for some type `E`, and either there are no other parameters or else all other parameters have default arguments (8.3.6 [dcl.fct.default]). [Note: Initializer-list constructors are favored over other constructors in list-initialization (13.3.1.7 [over.match.list]). Given a class `C`, a constructor template such as `template<class T> C(T)` is never instantiated to produce an initializer-list constructor, because an initializer list argument causes the corresponding parameter to be a non-deduced context (14.8.2.1 [temp.deduct.call]). —end note] The template `std::initializer_list` is not predefined;...

#### 1514. Ambiguity between enumeration definition and zero-length bit-field

Section: 9.6 [class.bit] Status: tentatively ready Submitter: John Spicer Date: 2012-07-03

Consider an example like:

      struct S {
        typedef int T;
        enum E : T {};
        enum E : T {};    // #1
      };

The declaration at #1 is ambiguous: it could either be an invalid redefinition of `enum E` or a zero-length bit-field of type `enum E` (since `T{}` is zero-valued constant expression). The current Standard does not appear to have a rule to disambiguate the two.

Proposed resolution (October, 2012):

Change 7.2 [dcl.enum] paragraph 1 as follows:

> ...the attributes in that attribute-specifier-seq are thereafter considered attributes of the enumeration whenever it is named. In a member-specification, an ambiguity can arise from the similarity between the declaration of an enumeration with an enum-base and the declaration of a zero-length unnamed bit-field of enumeration type. The ambiguity appears as a choice between an enum-specifier and a member-declaration for a bit-field. The resolution is that a `:` following `enum` identifier is parsed as part of an enum-base. [Example:

>       struct S {
>         enum E : int {};
>         enum E : int {};  // error: redeclaration of enumeration
>       };

> —end example]

#### 1492. Exception specifications on template destructors

Section: 12.4 [class.dtor] Status: tentatively ready Submitter: Jason Merrill Date: 2012-04-01

According to 12.4 [class.dtor] paragraph 3,

> A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4 [except.spec]).

The implications of this are not clear for the destructor of a class template. For example,

      template <class T> struct B: T {
        ~B();
      };
      template <class T> B<T>::~B() noexcept {}

The implicit exception-specification of the in-class declaration of the destructor depends on the characteristics of the template argument. Does this mean that the out-of-class definition of the destructor is ill-formed, or will it be ill-formed only in specializations where the template argument causes the implicit exception-specification to be other than `noexcept`?

Proposed resolution (October, 2012):

This issue is resolved by the resolution of issue 1552.

#### 1473. Syntax of literal-operator-id

Section: 13.5.8 [over.literal] Status: tentatively ready Submitter: Richard Smith Date: 2012-03-05

The current grammar requires that there be no whitespace between the literal and the ud-suffix, e.g., `""_abc`, but that there be whitespace between the `""` and the identifier in a literal-operator-id, e.g., `operator "" _abc`. This seems unfortunate. Would it be possible to provide an alternate production,

`operator` user-defined-string-literal

with the requirement that the string-literal be empty?

The current wording is also unclear regarding interactions with phases of translation. We have the following production:

literal-operator-id:

`operator ""` identifier

As this is after translation phase 6, would something like

      operator "" "" _foo

be accepted?

Proposed resolution (October, 2012):

1. Change 13.5.8 [over.literal] as follows:

literal-operator-id:

`operator ""` string-literal identifier
`operator` user-defined-string-literal

2. Change 13.5.8 [over.literal] paragraph 1 as follows:

> The string-literal or user-defined-string-literal in a literal-operator-id shall have no encoding-prefix and shall contain no characters other than the implicit terminating `'\0'`. The ud-suffix of the user-defined-string-literal or the identifier in a literal-operator-id is called a literal suffix identifier. [Note: some literal suffix identifiers are reserved for future standardization; see 17.6.4.3.5 [usrlit.suffix]. —end note]

3. Change the example in 13.5.8 [over.literal] paragraph 8 as follows:

      void operator "" _km(long double);                  // OK
      string operator "" _i18n(const char*, std::size_t); // OK
      template <char...> int operator "" \u03C0();        // OK: UCN for lowercase pi
      float operator ""E(const char*);                    // error: ""E (with no intervening space)
                                                          // is a single token OK
      float operator " " B(const char*);                  // error: non-adjacent quotesempty string-literal
      string operator "" 5X(const char*, std::size_t);    // error: invalid literal suffix identifier
      double operator "" _miles(double);                  // error: invalid parameter-declaration-clause
      template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause

#### 1471. Nested type of non-dependent base

Section: 14.6.2.1 [temp.dep.type] Status: tentatively ready Submitter: Johannes Schaub Date: 2012-02-26

Even though `A::C` is a nested type and member of the current instantiation, and thus dependent by the rules of 14.6.2.1 [temp.dep.type] paragraph 8, there does not seem to be a good reason for making it so:

      struct B {
       struct C { };
      };

      template<typename T> struct A : B {
       A::C c;
      };

Proposed resolution (October, 2012):

[Some existing uses of the term “member of the current instantiation” are consistent with the definition in 14.6.2.1 [temp.dep.type] paragraph 4; others are intended to refer to members of the “current instantiation,” as defined in paragraph 1. The following resolution changes the latter to use the phrase “member of a class that is the current instantiation.”]

1. Change 14.6.2.1 [temp.dep.type] paragraph 4 as follows:

> A name is a member of the current instantiation if it is

> - An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [Note: This can only occur when looking up a name in a scope enclosed by the definition of a class template. —end note]

> - A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [Note: if no such member is found, and the current instantiation has any dependent base classes, then the qualified-id is a member of an unknown specialization; see below. —end note]

> - An id-expression denoting the member in a class member access expression (5.2.5 [expr.ref]) for which the type of the object expression is the current instantiation, and the id-expression, when looked up (3.4.5 [basic.lookup.classref]), refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [Note: if no such member is found, and the current instantiation has any dependent base classes, then the id-expression is a member of an unknown specialization; see below. —end note]

> [Example: ... —end example]

> A name is a dependent member of the current instantiation if it is a member of the current instantiation which, when looked up, refers to at least one member of a class that is the current instantiation.

2. Change 14.6.2.1 [temp.dep.type] paragraph 5 as follows:

> A name is a member of an unknown specialization if it is

> - A qualified-id in which the nested-name-specifier names a dependent type that is not the current instantiation.

> - A qualified-id in which the nested-name-specifier refers to the current instantiation, the current instantiation has at least one dependent base class, and name lookup of the qualified-id does not find any member of a class that is the current instantiation or a non-dependent base class thereof.

> - An id-expression denoting the member in a class member access expression (5.2.5 [expr.ref]) in which either

> - the type of the object expression is the current instantiation, the current instantiation has at least one dependent base class, and name lookup of the id-expression does not find a member of a class that is the current instantiation or a non-dependent base class thereof; or

> - the type of the object expression is dependent and is not the current instantiation.

3. Change 14.6.2.1 [temp.dep.type] paragraph 8 as follows:

> A type is dependent if it is

> - ...

> - a nested class or enumeration that is a dependent member of the current instantiation,

> - ...

4. Change 14.6.2.2 [temp.dep.expr] paragraph 3 as follows:

> An id-expression is type-dependent if it contains

> - ...

> or if it names a static data dependent member of the current instantiation that has is a static data member of type “array of unknown bound of `T`” for some `T` (14.5.1.3 [temp.static]). Expressions of the following forms...

5. Change 14.6.2.3 [temp.dep.constexpr] paragraph 2 as follows (assumes the base text is as modified by issue 1413):

> An id-expression is value-dependent if:

> - it is a name declared with a dependent type,

> - it is the name of a non-type template parameter,

> - it names a member of an unknown specialization,

> - it names a static data member of the current instantiation that is a dependent member of the current instantiation and is not initialized in a member-declarator,

> - it names a static member function that is a dependent member of the current instantiation, or

> - it is a constant with literal type and is initialized with an expression that is value-dependent.

> Expressions of the following form...

6. Change 14.6.2.3 [temp.dep.constexpr] paragraph 5 as follows (assumes the base text is as modified by issue 1413):

> An expression of the form `&`qualified-id where the qualified-id's nested-name-specifier names a dependent member of the current instantiation is value-dependent.

#### 1484. Unused local classes of function templates

Section: 14.7.1 [temp.inst] Status: tentatively ready Submitter: Johannes Schaub Date: 2012-03-25

Do local classes of function templates get the same treatment as member classes of class templates? In particular, is their definition only instantiated when they are required? For example,

      template<typename T> void f() {
        struct B {
          T t;
        };
      }

      int main() {
        f<void>();
      }

Implementations vary on this question.

(This question is superficially similar to the one in issue 1253. However, the entities in view in that issue can be named and defined outside the containing template and thus can be explicitly specialized, none of which is true for local classes of function templates.)

It should also be noted that the resolution of this issue should apply as well to local enumeration types.

Proposed resolution (October, 2012):

Change 14.7.1 [temp.inst] paragraph 1 as follows:

> Unless a class template specialization has been explicitly instantiated (14.7.2 [temp.explicit]) or explicitly specialized (14.7.3 [temp.expl.spec]), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. [Note: Within a template declaration, a local class or enumeration and the members of a local class are never considered to be entities that can be separately instantiated (this includes their default arguments, exception-specifications, and non-static data member initializers, if any). As a result, the dependent names are looked up, the semantic constraints are checked, and any templates used are instantiated as part of the instantiation of the entity within which the local class or enumeration is declared. —end note] The implicit instantiation of a class template specialization...

#### 1462. Deduction failure vs “ill-formed, no diagnostic required”

Section: 14.8.2 [temp.deduct] Status: tentatively ready Submitter: John Spicer Date: 2012-02-08

The relationship between errors that render a program ill-formed but for which no diagnostic is required and things that cause deduction failure is not clearly specified. Presumably failures that need not be diagnosed cannot be the basis for SFINAE, lest different implementations perform deduction differently depending on how thoroughly they handle such cases. This should be spelled out explicitly.

Proposed resolution (October, 2012):

Change 14.8.2 [temp.deduct] paragraph 8 as follows:

> If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [Note: If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution process. —end note] Only invalid types and expressions...

#### 1356. Exception specifications of copy assignment operators with virtual bases

Section: 15.4 [except.spec] Status: tentatively ready Submitter: Sean Hunt Date: 2011-08-16

It is unspecified if an implicitly-defined copy assignment operator directly invokes the copy assignment operators of virtual bases. The exception-specification of such a copy assignment operator is thus also unspecified. The specification in 15.4 [except.spec] paragraph 14 should explicitly include the exceptions from the copy assignment operators of virtual base classes, regardless of whether the implicit definition actually invokes the virtual base assignment operators or not.

Proposed resolution (October, 2012):

This issue is resolved by the resolution of issue 1351.

### Issues with "Review" Status

#### 974. Default arguments for lambdas

Section: 5.1.2 [expr.prim.lambda] Status: review Submitter: Jason Merrill Date: 4 September, 2009
N3092 comment US 29

There does not appear to be any technical difficulty that would require the restriction in 5.1.2 [expr.prim.lambda] paragraph 5 against default arguments in lambda-expressions.

Proposed resolution (August, 2011):

Delete the following sentence from 5.1.2 [expr.prim.lambda] paragraph 5:

> Default arguments (8.3.6 [dcl.fct.default]) shall not be specified in the parameter-declaration-clause of a lambda-declarator.

Additional note (February, 2012):

EWG requested that the adoption of this proposed resolution be postponed to allow them to discuss it. The issue has thus been returned to "review" status pending EWG action.

#### 975. Restrictions on return type deduction for lambdas

Section: 5.1.2 [expr.prim.lambda] Status: review Submitter: Jason Merrill Date: 4 September, 2009
N3092 comment US 30

There does not appear to be any technical difficulty that would require the current restriction that the return type of a lambda can be deduced only if the body of the lambda consists of a single return statement. In particular, multiple return statements could be permitted if they all return the same type.

Proposed resolution (August, 2011):

Change 5.1.2 [expr.prim.lambda] paragraph 4 as follows:

> ...If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:

> - if the compound-statement is of the form

>   `{` attribute-specifier-seqopt `return` expression `;`

>   the type of the returned expression after lvalue-to-rvalue conversion (4.1 [conv.lval]), array-to-pointer conversion (4.2 [conv.array]), and function-to-pointer conversion (4.3 [conv.func]);

> - otherwise, `void`.

> - if there are no `return` statements in the compound-statement, or all `return` statements return either an expression of type `void` or no expression or braced-init-list, the type `void`;

> - otherwise, if all `return` statements return an expression and the types of the returned expressions after lvalue-to-rvalue conversion (4.1 [conv.lval]), array-to-pointer conversion (4.2 [conv.array]), and function-to-pointer conversion (4.3 [conv.func]) are the same, that common type;

> - otherwise, the program is ill-formed.

> [Example:

>       auto x1 = [](int i){ return i; }; // OK: return type is int
>       auto x2 = []{ return { 1, 2 }; }; // error: the return type is void (a
>                                         // braced-init-list is not an expression)
>       struct A { int fn1(); const int& fn2(); };
>       template <class T> void f () {
>         [](T t, bool b){
>           if (b)
>             return t.fn1();
>           else
>             return t.fn2();
>         };
>       }
>       template void f<A>();             // OK: lambda return type is int

> —end example]

Additional note (February, 2012):

EWG requested that the adoption of this proposed resolution be postponed to allow them to discuss it. The issue has thus been returned to "review" status pending EWG action.

#### 1512. Pointer comparison vs qualification conversions

Section: 5.9 [expr.rel] Status: review Submitter: Steve Clamage Date: 2012-06-22

According to 5.9 [expr.rel] paragraph 2, describing pointer comparisons,

> Pointer conversions (4.10 [conv.ptr]) and qualification conversions (4.4 [conv.qual]) are performed on pointer operands (or on a pointer operand and a null pointer constant, or on two null pointer constants, at least one of which is non-integral) to bring them to their composite pointer type.

This would appear to make the following example ill-formed,

      bool foo(int** x, const int** y) {
         return x < y;  // valid ?
      }

because `int**` cannot be converted to `const int**`, according to the rules of 4.4 [conv.qual] paragraph 4. This seems too strict for pointer comparison, and current implementations accept the example.

Proposed resolution (November, 2012):

The proposed wording is found in document N3478.

#### 1551. Wording problems in using-declaration specification

Section: 7.3.3 [namespace.udecl] Status: review Submitter: Richard Smith Date: 2012-09-06

There are at least a couple of problems with the current wording of 7.3.3 [namespace.udecl]. First is the use of the word “entity” to describe what the using-declaration represents. For example, in paragraph 1,

> If a using-declaration names a constructor (3.4.3.1 [class.qual]), it implicitly declares a set of constructors in the class in which the using-declaration appears (12.9 [class.inhctor]); otherwise the name specified in a using-declaration is a synonym for the name of some entity declared elsewhere.

An overload set of functions and function templates is not an “entity,” according to 3 [basic] paragraph 3. A better phrasing might be something like, “...a synonym for a set of declarations in a different declarative region.”

The other problem is in paragraph 11:

> The entity declared by a using-declaration shall be known in the context using it according to its definition at the point of the using-declaration. Definitions added to the namespace after the using-declaration are not considered when a use of the name is made.

This has the same problem with use of the term “entity,” and it also refers to “definitions” when presumably it means “declarations.”

Proposed resolution (October, 2012):

1. Add the following as a new paragraph after 3.3.2 [basic.scope.pdecl] paragraph 3:

> The point of declaration for a class or class template first declared by a class-specifier is immediately after the identifier or simple-template-id (if any) in its class-head (Clause 9 [class]). The point of declaration for an enumeration is immediately after the identifier (if any) in either its enum-specifier (7.2 [dcl.enum]) or its first opaque-enum-declaration (7.2 [dcl.enum]), whichever comes first. The point of declaration of an alias or alias template immediately follows the type-id to which the alias refers.

> The point of declaration of a using-declaration that does not name a constructor is immediately after the using-declaration (7.3.3 [namespace.udecl]).

2. Change 7.3.3 [namespace.udecl] paragraph 1 as follows:

> ...If a using-declaration names a constructor (3.4.3.1 [class.qual]), it implicitly declares a set of constructors in the class in which the using-declaration appears (12.9 [class.inhctor]); otherwise the name specified in a using-declaration is a synonym for the name of some entity declared elsewhere a set of declarations in another namespace or class.

3. Change 7.3.3 [namespace.udecl] paragraph 11 as follows:

> The entity declared by a using-declaration shall be known in the context using it according to its definition at the point of the using-declaration. Definitions Declarations added to the namespace after the using-declaration are not considered when a use of the name is made. [Note: Thus, additional overloads and default arguments (8.3.6 [dcl.fct.default]) added after the using-declaration are ignored, but template specializations (14.5.5 [temp.class.spec], 14.7.3 [temp.expl.spec]) are considered. —end note] [Example:...

Additional note (October, 2012):

The note added by this resolution to 7.3.3 [namespace.udecl] paragraph 11 regarding the treatment of default arguments directly contradicts the normative statement of 8.3.6 [dcl.fct.default] paragraph 9:

> When a declaration of a function is introduced by way of a using-declaration (7.3.3 [namespace.udecl]), any default argument information associated with the declaration is made known as well. If the function is redeclared thereafter in the namespace with additional default arguments, the additional arguments are also known at any point following the redeclaration where the using-declaration is in scope.

The issue has been returned to "review" status for reconciliation of these two passages.

#### 1287. Direct initialization vs “implicit” conversion in reference binding

Section: 8.5.3 [dcl.init.ref] Status: review Submitter: Daniel Krügler Date: 2011-04-06

In 8.5.4 [dcl.init.list] paragraph 5, both the cases in which a reference can be bound to the result of a conversion function use the phrase “can be implicitly converted to...” This is confusing, as it could be read as excluding `explicit` conversion functions. However, that appears not to be the intent, as 13.3.1.6 [over.match.ref], which is cited in these cases, allows `explicit` conversion functions for direct-initialization.

Proposed resolution (August, 2011):

Change the two indicated (not contiguous) sub-bullets of 8.5.3 [dcl.init.ref] paragraph 5 as follows:

- has a class type (i.e., `T2` is a class type), where `T1` is not reference-related to `T2`, and can be implicitly converted to an lvalue of type “cv3 `T3`,”...

- has a class type (i.e., `T2` is a class type), where `T1` is not reference-related to `T2`, and can be implicitly converted to an xvalue, class prvalue, or function lvalue of type “cv3 `T3`”, where “cv1 `T1`” is reference-compatible with “cv3 `T3`” (see 13.3.1.6 [over.match.ref]),

Additional note, January, 2012:

Questions have been raised regarding the consistency of the treatment of class prvalues in this resolution with other types . The issue is thus being returned to "review" status for additional discussion.

Proposed resolution (February, 2012):

1. Change 8.5.3 [dcl.init.ref] paragraph 5 as follows:

> A reference to type “cv1 `T1`” is initialized by an expression of type “cv2 `T2`” as follows:

> - If the reference is an lvalue reference and the initializer expression

> - is an lvalue (but is not a bit-field), and “cv1 `T1`” is reference-compatible with “cv2 `T2`,” or

> - has a class type (i.e., `T2` is a class type), where `T1` is not reference-related to `T2`, and can be implicitly converted to an lvalue of type “cv3 `T3`,” where “cv1 `T1`” is reference-compatible with “cv3 `T3`”106 (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6 [over.match.ref]) and choosing the best one through overload resolution (13.3 [over.match])),

> then the reference is bound...

> - Otherwise, the reference shall be...

> - If the initializer expression

> - is an xvalue, class prvalue, array prvalue or function lvalue and “cv1 `T1`” is reference-compatible with “cv2 `T2`”, or

> - has a class type (i.e., `T2` is a class type), where `T1` is not reference-related to `T2`, and can be implicitly converted to an xvalue, class prvalue, or function lvalue of type “cv3 `T3`”, where “cv1 `T1`” is reference-compatible with “cv3 `T3`” (see 13.3.1.6 [over.match.ref]),

> then the reference is bound... [Example:

>       struct A { };
>       struct B : A { } b;
>       extern B f();
>       const A& rca2 = f();    // bound to the A subobject of the B rvalue.
>       A&& rra = f();          // same as above
>       struct X {
>         operator B();
>         operator int&();
>       } x;
>       const A& r = x;         // bound to the A subobject of the result of the conversion
>       int i2 = 42;
>       int&& rri = static_cast<int&&>(i2); // bound directly to i2
>       B&& rrb = x;            // bound directly to the result of operator B
>       int&& rri2 = X();       // error: lvalue-to-rvalue conversion applied to the
>                               // result of operator int&

> —end example]

> - Otherwise, a temporary... [Example:

>       const A& r = x;         // r refers to a temporary
>       B&& rrb = x;            // rrb refers to a temporary

>       const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
>       double&& rrd = 2;       // rrd refers to temporary with value 2.0
>       ...

2. Change 13.3.1.6 [over.match.ref] paragraph 1 as follows:

> Under the conditions specified in 8.5.3 [dcl.init.ref], a reference can be bound directly to a glvalue or class prvalue that is the result of applying a conversion function...

> - The conversion functions of `S` and its base classes are considered, except that for copy-initialization, only the non-explicit conversion functions are considered. Those that are not hidden within `S` and yield type “lvalue reference to cv2 `T2`” (when 8.5.3 [dcl.init.ref] requires an lvalue result) or “cv2 `T2`” or “rvalue reference to cv2 `T2`” (when 8.5.3 [dcl.init.ref] requires an rvalue result), where “cv1 `T`” is reference-compatible (8.5.3 [dcl.init.ref]) with “cv2 `T2`”, are candidate functions.

#### 1402. Move functions too often deleted

Section: 12.8 [class.copy] Status: review Submitter: Daniel Krügler Date: 2011-10-03

Paragraphs 11 and 23 of 12.8 [class.copy] make a defaulted move constructor and assignment operator, respectively, deleted if there is a subobject with no corresponding move function and for which the copy operation is non-trivial. This seems excessive and unnecessary. For example:

        template<typename T>
         struct wrap
         {
          wrap() = default;

        #ifdef USE_DEFAULTED_MOVE
          wrap(wrap&&) = default;
        #else
          wrap(wrap&& w) : t(static_cast<T&&>(w.t)) { }
        #endif

          wrap(const wrap&) = default;

          T t;
         };

        struct S {
          S(){}
          S(const S&){}
          S(S&&){}
        };

        typedef wrap<const S> W;

        W get() { return W(); }  // Error, if USE_DEFAULTED_MOVE is defined, else OK

In this example the defaulted move constructor of `wrap` is selected by overload resolution, but this move-constructor is deleted, because `S` has no trivial copy-constructor.

I think that we overshoot here with the delete rules: I see no problem for the defaulted move-constructor in this example. Our triviality-deduction rules already cover this case (12.8 [class.copy] paragraph 12: `W::W(W&&)` is not trivial) and our exception-specification rules (15.4 [except.spec] paragraph 14) already correctly deduce a `noexcept(false)` specification for `W::W(W&&)`.

It would still be OK to prevent that a move-constructor would be generated for the following example where no user-declared defaulted copy/move members are present:

        template<typename T>
         struct wrap_2
         {
          wrap_2() = default;
          T t;
         };

        typedef wrap_2<const S> W2;

        W2 get() { return W2(); }  // OK, selects copy constructor

if we want. This would mean that we add a new bullet to 12.8 [class.copy] paragraph 9 and paragraph 20.

Proposed resolution (February, 2012):

1. Change 12.8 [class.copy] paragraph 9 as follows:

> If the definition of a class `X` does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

> - ...

> - X does not have a user-declared destructor, and

> - the move constructor would not be implicitly defined as deleted., and

> - each of `X`'s non-static data members and direct or virtual base classes has a type that either has a move constructor or is trivially copyable.

> [Note:...

2. Change 12.8 [class.copy] paragraph 11 as follows:

> An implicitly-declared copy/move constructor is an `inline public` member of its class. A defaulted copy/move constructor for a class `X` is defined as deleted (8.4.3 [dcl.fct.def.delete]) if `X` has:

> - ...

> - any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor, or

> - for the copy constructor, a non-static data member of rvalue reference type., or

> - for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.

3. Change 12.8 [class.copy] paragraph 20 as follows:

> If the definition of a class `X` does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if

> - ...

> - `X` does not have a user-declared destructor, and

> - the move assignment operator would not be implicitly defined as deleted.,

> - `X` has no direct or indirect virtual base class with a non-trivial move assignment operator, and

> - each of `X`'s non-static data members and direct or virtual base classes has a type that either has a move assignment operator or is trivially copyable.

> Example:...

4. Change 12.8 [class.copy] paragraph 23 as follows:

> A defaulted copy/move assignment operator for class `X` is defined as deleted if `X` has:

> - ...

> - a direct or virtual base class `B` that cannot be copied/moved because overload resolution (13.3 [over.match]), as applied to `B`'s corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator., or

> - for the move assignment operator, a non-static data member or direct base class with a type that does not have a move assignment operator and is not trivially copyable, or any direct or indirect virtual base class.

Additional notes (August, 2012):

The proposed resolution was extensively discussed and additional alternatives were suggested. A paper is being produced for the October, 2012 meeting describing the various options, so the issue has been returned to "review" status to wait for the outcome of that deliberation.

See also the discussion of issue 1491 for additional considerations.

#### 1567. Inheriting constructors and copy/move constructors

Section: 12.9 [class.inhctor] Status: review Submitter: Jason Merrill Date: 2012-10-10

According to 12.9 [class.inhctor] paragraph 3,

> For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the class where the using-declaration appears.

It seems that this should be suppressing constructors that would be copy/move constructors in the derived class rather than copy/move constructors in the base class. For example:

      struct B;
      struct A {
        A(const A&);
        A(const B&);
        A(int);
      };

      struct B: A {
        using A::A;
      };

If `B::B(const B&)` is an inheriting constructor, other subobjects of `B` will not be copied. Also, if `A::A(const A&)` is not inherited, `B` objects cannot be constructed from an `A` object.

Proposed resolution (October, 2012):

Change 12.9 [class.inhctor] paragraph 3 as follows:

> For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class..

#### 1351. Problems with implicitly-declared exception-specifications

Section: 15.4 [except.spec] Status: review Submitter: Richard Smith Date: 2011-08-16

The determination of the exception-specification for an implicitly-declared special member function, as described in 15.4 [except.spec] paragraph 14, does not take into account the fact that nonstatic data member initializers and default arguments in default constructors can contain throw-expressions, which are not part of the exception-specification of any function that is “directly invoked” by the implicit definition. Also, the reference to “directly invoked” functions is not restricted to potentially-evaluated expressions, thus possibly including irrelevant exception-specifications.

Additional note (August, 2012):

The direction established by CWG for resolving this issue was to consider functions called from default arguments and non-static data member initializers in determining the exception-specification. This leads to a problem with ordering: because non-static data member initializers can refer to members declared later, their effect cannot be known until the end of the class. However, a non-static data member initializer could possibly refer to an implicitly-declared constructor, either its own or that of an enclosing class.

Proposed resolution (October, 2012):

1. Add the following two new paragraphs and make the indicated changes to 15.4 [except.spec] paragraph 14:

> A set of potential exceptions may contain types and the special value “any.” The set of potential exceptions of an expression is the union of all sets of potential exceptions of each potentially-evaluated subexpression `e`:

> - If `e` is a call to a function, member function, function pointer, or member function pointer (including implicit calls, such as a call to the allocation function in a new-expression):

> - if it has a non-throwing exception-specification or the call is a core constant expression (5.19 [expr.const]), the set is empty;

> - otherwise, if it has a dynamic-exception-specification, the set consists of every type in that dynamic-exception-specification;

> - otherwise, the set consists of “any.”

> - If `e` is a throw-expression (15.1 [except.throw]), the set consists of the type of the exception object that would be initialized by the operand if present, or “any” otherwise.

> - If `e` is a `dynamic_cast` expression that casts to a reference type and requires a run-time check (5.2.7 [expr.dynamic.cast]), the set consists of the type `std::bad_cast`.

> - If `e` is a `typeid` expression applied to a glvalue expression whose type is a polymorphic class type (5.2.8 [expr.typeid]), the set consists of the type `std::bad_typeid`.

> - If `e` is a new-expression with a non-constant expression in the noptr-new-declarator (5.3.4 [expr.new]), the set also includes the type `std::bad_array_new_length`.

> - Otherwise, the set is the empty set.

> The set of potential exceptions of a function `f` of some class `X`, where `f` is an inheriting constructor or an implicitly-declared special member function, is defined as follows:

> - If `f` is a constructor, the set is the union of the sets of potential exceptions of the constructor invocations for `X`'s non-variant non-static data members, for `X`'s direct base classes, and, if `X` is non-abstract (10.4 [class.abstract]), for `X`'s virtual base classes, as selected by overload resolution for the implicit definition of `f` (12.1 [class.ctor]), including default argument expressions used in such invocations. [Note: Even though destructors for fully constructed subobjects are invoked when an exception is thrown during the execution of a constructor (15.2 [except.ctor]), their exception-specifications do not contribute to the exception-specification of the constructor, because an exception thrown from such a destructor could never escape the constructor (15.1 [except.throw], 15.5.1 [except.terminate]). —end note]

> - If `f` is a default constructor or inheriting constructor, the set also contains all members of the sets of potential exceptions of the initialization of non-static data members from brace-or-equal-initializers.

> - If `f` is an assignment operator, the set is the union of the sets of potential exceptions of the assignment operator invocations for `X`'s non-variant non-static data members and for `X`'s virtual and direct base classes, as selected by overload resolution for the implicit definition of `f` (12.8 [class.copy]), including default argument expressions used in such invocations.

> - If `f` is a destructor, the set is the union of the sets of potential exceptions of the destructor invocations for `X`'s non-variant non-static data members and for `X`'s virtual and direct base classes.

> An inheriting constructor (12.9 [class.inhctor]) and an implicitly declared implicitly-declared special member function (Clause 12 [special]) have an are considered to have an implicit exception-specification. If `f` is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id `T` if and only if `T` is allowed by the exception-specification of a function directly invoked by `f`'s implicit definition; `f` allows all exceptions if any function it directly invokes allows all exceptions, and `f` has the exception-specification `noexcept(true)` if every function it directly invokes allows no exceptions. The implicit exception-specification is `noexcept(false)` if the set of potential exceptions of the function contains “any;” otherwise, if that set contains at least one type, the implicit exception-specification specifies each type T contained in the set; otherwise, the implicit exception-specification is `noexcept(true)`. [Note: An instantiation of an inheriting constructor template has an implied exception-specification as if it were a non-template inheriting constructor. —end note] [Example:

>       struct A {
>         A();
>         A(const A&) throw();
>         A(A&&) throw();
>         ~A() throw(X);
>       };
>       struct B {
>         B() throw();
>         B(const B&) throw();
>         B(B&&, int = (throw Y(), 0)) throw(Y) noexcept;
>         ~B() throw(Y);
>       };
>       struct D : public A, public B {
>           // Implicit declaration of D::D();
>           // Implicit declaration of D::D(const D&) noexcept(true);
>           // Implicit declaration of D::D(D&&) throw(Y);
>           // Implicit declaration of D::~D() throw(X, Y);
>       };

> Furthermore, if...

2. Change 5.3.7 [expr.unary.noexcept] paragraph 3 as follows:

> The result of the noexcept operator is `false` if in a potentially-evaluated context the set of potential exceptions of the expression (15.4 [except.spec]) would contain contains “any” or at least one type and `true` otherwise.

> - a potentially evaluated call80 to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (15.4 [except.spec]), unless the call is a constant expression (5.19 [expr.const]),

> - a potentially evaluated throw-expression (15.1 [except.throw]),

> - a potentially evaluated `dynamic_cast` expression `dynamic_cast<T>(v)`, where `T` is a reference type, that requires a run-time check (5.2.7 [expr.dynamic.cast]), or

> - a potentially evaluated `typeid` expression (5.2.8 [expr.typeid]) applied to a glvalue expression whose type is a polymorphic class type (10.3 [class.virtual]).

> Otherwise, the result is `true`.

(This resolution also resolves issues 1356 and 1465.)

Additional note (October, 2012):

The preceding wording has been modified from the version that was reviewed following the October, 2012 meeting and thus has been returned to "review" status.

### Issues with "Drafting" Status

#### 1509. Definition of “non-template function”

Section: 1.3 [intro.defs] Status: drafting Submitter: Johannes Schaub Date: 2012-06-08

The term “non-template function” is used in various places but never defined.

#### 1531. Definition of “access” (verb)

Section: 1.3 [intro.defs] Status: drafting Submitter: Mike Miller Date: 2012-07-27

The verb “access” is used in various places in the Standard (see 3.8 [basic.life] paragraphs 5 and 6 and 3.10 [basic.lval] paragraph 10) but is not defined. C99 defines it as

> <execution-time action> to read or modify the value of an object

(See also issue 1530.)

#### 1343. Sequencing of non-class initialization

Section: 1.9 [intro.execution] Status: drafting Submitter: Johannes Schaub Date: 2011-08-12

The current wording does not indicate that initialization of a non-class object is a full-expression, but presumably should do so.

#### 1332. Handling of invalid universal-character-names

Section: 2.3 [lex.charset] Status: drafting Submitter: Mike Miller Date: 2011-06-20

According to 2.3 [lex.charset] paragraph 2,

> The character designated by the universal-character-name `\UNNNNNNNN` is that character whose character short name in ISO/IEC 10646 is `NNNNNNNN`; the character designated by the universal-character-name `\uNNNN` is that character whose character short name in ISO/IEC 10646 is `0000NNNN`. If the hexadecimal value for a universal-character-name corresponds to a surrogate code point (in the range 0xD800-0xDFFF, inclusive), the program is ill-formed. Additionally, if the hexadecimal value for a universal-character-name outside the c-char-sequence, s-char-sequence, or r-char-sequence of a character or string literal corresponds to a control character (in either of the ranges 0x00-0x1F or 0x7F-0x9F, both inclusive) or to a character in the basic source character set, the program is ill-formed.

It is not specified what should happen if the hexadecimal value does not designate a Unicode code point: is that undefined behavior or does it make the program ill-formed?

As an aside, a note should be added explaining why these requirements apply to to an r-char-sequence when, as the footnote at the end of the paragraph explains,

> A sequence of characters resembling a universal-character-name in an r-char-sequence (2.14.5 [lex.string]) does not form a universal-character-name.

#### 369. Are `new`/`delete` identifiers or preprocessing-op-or-punc?

Section: 2.5 [lex.pptoken] Status: drafting Submitter: Martin v. Loewis Date: 30 July 2002

2.5 [lex.pptoken] paragraph 2 specifies that there are 5 categories of tokens in phases 3 to 6. With 2.13 [lex.operators] paragraph 1, it is unclear whether `new` is an identifier or a preprocessing-op-or-punc; likewise for `delete`. This is relevant to answer the question whether

    #define delete foo

is a well-formed control-line, since that requires an identifier after the `define` token.

(See also issue 189.)

#### 189. Definition of operator and punctuator

Section: 2.13 [lex.operators] Status: drafting Submitter: Mike Miller Date: 20 Dec 1999

The nonterminals operator and punctuator in 2.7 [lex.token] are not defined. There is a definition of the nonterminal operator in 13.5 [over.oper] paragraph 1, but it is apparent that the two nonterminals are not the same: the latter includes keywords and multi-token operators and does not include the nonoverloadable operators mentioned in paragraph 3.

There is a definition of preprocessing-op-or-punc in 2.13 [lex.operators] , with the notation that

> Each preprocessing-op-or-punc is converted to a single token in translation phase 7 (2.1).

However, this list doesn't distinguish between operators and punctuators, it includes digraphs and keywords (can a given token be both a keyword and an operator at the same time?), etc.

Suggested resolution:

1. Change 13.5 [over.oper] to use the term overloadable-operator.
2. Change 2.7 [lex.token] to use the term operator-token instead of operator (since there are operators that are keywords and operators that are composed of more than one token).
3. Change 2.13 [lex.operators] to define the nonterminals operator-token and punctuator.

Additional note (April, 2005):

The resolution for this problem should also address the fact that `sizeof` and `typeid` (and potentially others like `decltype` that may be added in the future) are described in some places as “operators” but are not listed in 13.5 [over.oper] paragraph 3 among the operators that cannot be overloaded.

(See also issue 369.)

#### 1529. Nomenclature for variable vs reference non-static data member

Section: 3 [basic] Status: drafting Submitter: Daniel Krügler Date: 2012-07-24

According to 3 [basic] paragraph 6,

> A variable is introduced by the declaration of a reference other than a non-static data member or of an object.

In other words, non-static data members of reference type are not variables. This complicates the wording in a number of places, where the text refers to “variable or data member,” presumably to cover the reference case, but that phrasing could lead to the mistaken impression that all data members are not variables. It would be better if either there were a term for the current phrase “variable or data member” or if there were a less-unwieldy term for “non-static data member of reference type” that could be used in place of “data member” in the current phrasing.

#### 554. Definition of “declarative region” and “scope”

Section: 3.3 [basic.scope] Status: drafting Submitter: Gabriel Dos Reis Date: 29 December 2005

The various uses of the term “declarative region” throughout the Standard indicate that the term is intended to refer to the entire block, class, or namespace that contains a given declaration. For example, 3.3 [basic.scope] paragraph 2 says, in part:

> [Example: in

>         int j = 24;
>         int main()
>         {
>             int i = j, j;
>             j = 42;
>         }

> The declarative region of the first `j` includes the entire example... The declarative region of the second declaration of `j` (the `j` immediately before the semicolon) includes all the text between `{` and `}`...

However, the actual definition given for “declarative region” in 3.3 [basic.scope] paragraph 1 does not match this usage:

> Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity.

Because (except in class scope) a name cannot be used before it is declared, this definition contradicts the statement in the example and many other uses of the term throughout the Standard. As it stands, this definition is identical to that of the scope of a name.

The term “scope” is also misused. The scope of a declaration is defined in 3.3 [basic.scope] paragraph 1 as the region in which the name being declared is valid. However, there is frequent use of the phrase “the scope of a class,” not referring to the region in which the class's name is valid but to the declarative region of the class body, and similarly for namespaces, functions, exception handlers, etc. There is even a mention of looking up a name “in the scope of the complete postfix-expression” (3.4.5 [basic.lookup.classref] paragraph 3), which is the exact inverse of the scope of a declaration.

This terminology needs a thorough review to make it logically consistent. (Perhaps a discussion of the scope of template parameters could also be added to section 3.3 [basic.scope] at the same time, as all other kinds of scopes are described there.)

Proposed resolution (November, 2006):

1. Change 3.3 [basic.scope] paragraph 1 as follows:

> Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity a statement, block, function declarator, function-definition, class, handler, template-declaration, template-parameter-list of a template template-parameter, or namespace. In general, each particular name is valid may be used as an unqualified name to refer to the entity of its declaration or to the label only within some possibly discontiguous portion of program text called its scope. To determine the scope of a declaration...

2. Change 3.3 [basic.scope] paragraph 3 as follows:

> The names declared by a declaration are introduced into the scope in which the declaration occurs declarative region that directly encloses the declaration, except that declaration-statements, function parameter names in the declarator of a function-definition, exception-declarations (3.3.3 [basic.scope.local]), the presence of a `friend` specifier (11.3 [class.friend]), certain uses of the elaborated-type-specifier (7.1.6.3 [dcl.type.elab]), and using-directives (7.3.4 [namespace.udir]) alter this general behavior.

3. Change 3.3.3 [basic.scope.local] paragraphs 1-3 and add a new paragraph 4 before the existing paragraph 4 as follows:

> A name declared in a block (6.3 [stmt.block]) is local to that block. Its potential scope begins at its point of declaration (3.3.2 [basic.scope.pdecl]) and ends at the end of its declarative region. The declarative region of a name declared in a declaration-statement is the directly enclosing block (6.3 [stmt.block]). Such a name is local to the block.

> The potential scope declarative region of a function parameter name (including one appearing in the declarator of a function-definition or in a lambda-parameter-declaration-clause) or of a function-local predefined variable in a function definition (8.4 [dcl.fct.def]) begins at its point of declaration. If the function has a function-try-block the potential scope of a parameter or of a function-local predefined variable ends at the end of the last associated handler, otherwise it ends at the end of the outermost block of the function definition. A parameter name is the entire function definition or lambda-expression. Such a name is local to the function definition and shall not be redeclared in the any outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block function-body (including handlers of a function-try-block) or lambda-expression.

> The name in a `catch` exception-declaration The declarative region of a name declared in an exception-declaration is its entire handler. Such a name is local to the handler and shall not be redeclared in the outermost block of the handler.

> The potential scope of any local name begins at its point of declaration (3.3.2 [basic.scope.pdecl]) and ends at the end of its declarative region.

4. Change 3.3.5 [basic.funscope] as indicated:

> Labels (6.1 [stmt.label]) have function scope and may be used anywhere in the function in which they are declared except in members of local classes (9.8 [class.local]) of that function. Only labels have function scope.

5. Change 6.7 [stmt.dcl] paragraph 1 as follows:

> A declaration statement introduces one or more new identifiers names into a block; it has the form

> declaration-statement:
> block-declaration

> [Note: If an identifier a name introduced by a declaration was previously declared in an outer block, the outer declaration is hidden for the remainder of the block, after which it resumes its force (3.3.10 [basic.scope.hiding]). —end note]

[Drafting notes: This resolution deals almost exclusively with the unclear definition of “declarative region.” I've left the ambiguous use of “scope” alone for now. However sections 3.3.x all have headings reading “xxx scope,” but they don't mean the scope of a declaration but the different kinds of declarative regions and their effects on the scope of declarations contained therein. To me, it looks like most of 3.4 should refer to “declarative region” and not to “scope.”

The change to 6.7 fixes an “identifier” misuse (e.g., `extern T operator+(T,T);` at block scope introduces a name but not an identifier) and removes normative redundancy.]

#### 1482. Point of declaration of enumeration

Section: 3.3.2 [basic.scope.pdecl] Status: drafting Submitter: Daveed Vandevoorde Date: 2012-03-20

According to 3.3.2 [basic.scope.pdecl] paragraph 2,

> The point of declaration for an enumeration is immediately after the identifier (if any) in either its enum-specifier (7.2 [dcl.enum]) or its first opaque-enum-declaration (7.2 [dcl.enum]), whichever comes first.

This would make the following example well-formed:

      template<typename T> struct S { typedef char I; };
      enum E: S<E>::I { e };

Presumably that would make `E` an incomplete enumeration type for the instantiation of `S<E>` (a concept not otherwise found in the Standard). However, some implementations reject this example, presumably making the point of declaration after the enum-base. We either need to make it ill-formed or describe incomplete enumeration types.

See also issue 977.

#### 555. Pseudo-destructor name lookup

Section: 3.4 [basic.lookup] Status: drafting Submitter: Krzysztof Zelechowski Date: 26 January 2006

The Standard does not completely specify how to look up the type-name(s) in a pseudo-destructor-name (5.2 [expr.post] paragraph 1, 5.2.4 [expr.pseudo]), and what information it does have is incorrect and/or in the wrong place. Consider, for instance, 3.4.5 [basic.lookup.classref] paragraphs 2-3:

> If the id-expression in a class member access (5.2.5 [expr.ref]) is an unqualified-id, and the type of the object expression is of a class type `C` (or of pointer to a class type `C`), the unqualified-id is looked up in the scope of class `C`. If the type of the object expression is of pointer to scalar type, the unqualified-id is looked up in the context of the complete postfix-expression.

> If the unqualified-id is `~`type-name, and the type of the object expression is of a class type `C` (or of pointer to a class type `C`), the type-name is looked up in the context of the entire postfix-expression and in the scope of class `C`. The type-name shall refer to a class-name. If type-name is found in both contexts, the name shall refer to the same class type. If the type of the object expression is of scalar type, the type-name is looked up in the scope of the complete postfix-expression.

There are at least three things wrong with this passage with respect to pseudo-destructors:

1. A pseudo-destructor call (5.2.4 [expr.pseudo]) is not a “class member access”, so the statements about scalar types in the object expressions are vacuous: the object expression in a class member access is required to be a class type or pointer to class type (5.2.5 [expr.ref] paragraph 2).

2. On a related note, the lookup for the type-name(s) in a pseudo-destructor name should not be described in a section entitled “Class member access.”

3. Although the class member access object expressions are carefully allowed to be either a class type or a pointer to a class type, paragraph 2 mentions only a “pointer to scalar type” (disallowing references) and paragraph 3 deals only with a “scalar type,” presumably disallowing pointers (although it could possibly be a very subtle way of referring to both non-class pointers and references to scalar types at once).

The other point at which lookup of pseudo-destructors is mentioned is 3.4.3 [basic.lookup.qual] paragraph 5:

> If a pseudo-destructor-name (5.2.4 [expr.pseudo]) contains a nested-name-specifier, the type-names are looked up as types in the scope designated by the nested-name-specifier.

Again, this specification is in the wrong location (a pseudo-destructor-name is not a qualified-id and thus should not be treated in the “Qualified name lookup” section).

Finally, there is no place in the Standard that describes the lookup for pseudo-destructor calls of the form `p->T::~T()` and `r.T::~T()`, where `p` and `r` are a pointer and reference to scalar, respectively. To the extent that it gives any guidance at all, 3.4.5 [basic.lookup.classref] deals only with the case where the `~` immediately follows the `.` or `->`, and 3.4.3 [basic.lookup.qual] deals only with the case where the pseudo-destructor-name contains a nested-name-specifier that designates a scope in which names can be looked up.

See document J16/06-0008 = WG21 N1938 for further discussion of this and related issues, including 244, 305, 399, and 414.

Proposed resolution (June, 2008):

1. Add a new paragraph following 5.2 [expr.post] paragraph 2 as follows:

> When a postfix-expression is followed by a dot `.` or arrow `->` operator, the interpretation depends on the type `T` of the expression preceding the operator. If the operator is `.`, `T` shall be a scalar type or a complete class type; otherwise, `T` shall be a pointer to a scalar type or a pointer to a complete class type. When `T` is a (pointer to) a scalar type, the postfix-expression to which the operator belongs shall be a pseudo-destructor call (5.2.4 [expr.pseudo]); otherwise, it shall be a class member access (5.2.5 [expr.ref]).

2. Change 5.2.4 [expr.pseudo] paragraph 2 as follows:

> The left-hand side of the dot operator shall be of scalar type. The left-hand side of the arrow operator shall be of pointer to scalar type. This scalar type The type of the expression preceding the dot operator, or the type to which the expression preceding the arrow operator points, is the object type...

3. Change 5.2.5 [expr.ref] paragraph 2 as follows:

> For the first option (dot) the type of the first expression (the object expression) shall be “class object” (of a complete type) is a class type. For the second option (arrow) the type of the first expression (the pointer expression) shall be “pointer to class object” (of a complete type) is a pointer to a class type. In these cases, the id-expression shall name a member of the class or of one of its base classes.

4. Add a new paragraph following 3.4 [basic.lookup] paragraph 2 as follows:

> In a pseudo-destructor-name that does not include a nested-name-specifier, the type-names are looked up as types in the context of the complete expression.

5. Delete the last sentence of 3.4.5 [basic.lookup.classref] paragraph 2:

> If the id-expression in a class member access (5.2.5 [expr.ref]) is an unqualified-id, and the type of the object expression is of a class type `C`, the unqualified-id is looked up in the scope of class `C`. If the type of the object expression is of pointer to scalar type, the unqualified-id is looked up in the context of the complete postfix-expression.

Notes from the August, 2011 meeting:

The proposed resolution must be updated with respect to the current wording of the WP.

#### 192. Name lookup in parameters

Section: 3.4.1 [basic.lookup.unqual] Status: drafting Submitter: Alan Nash Date: 6 Jan 2000

The description of name lookup in the parameter-declaration-clause of member functions in 3.4.1 [basic.lookup.unqual] paragraphs 7-8 is flawed in at least two regards.

First, both paragraphs 7 and 8 apply to the parameter-declaration-clause of a member function definition and give different rules for the lookup. Paragraph 7 applies to names "used in the definition of a class `X` outside of a member function body...," which includes the parameter-declaration-clause of a member function definition, while paragraph 8 applies to names following the function's declarator-id (see the proposed resolution of issue 41), including the parameter-declaration-clause.

Second, paragraph 8 appears to apply to the type names used in the parameter-declaration-clause of a member function defined inside the class definition. That is, it appears to allow the following code, which was not the intent of the Committee:

        struct S {
            void f(I i) { }
            typedef int I;
        };

Additional note, January, 2012:

brace-or-equal-initializers for non-static data members are intended effectively as syntactic sugar for mem-initializers in constructor definitions; the lookup should be the same.

#### 156. Name lookup for conversion functions

Section: 3.4.5 [basic.lookup.classref] Status: drafting Submitter: Derek Inglis Date: 18 Aug 1999

Paragraph 7 of 3.4.5 [basic.lookup.classref] says,

> If the id-expression is a conversion-function-id, its conversion-type-id shall denote the same type in both the context in which the entire postfix-expression occurs and in the context of the class of the object expression (or the class pointed to by the pointer expression).

Does this mean that the following example is ill-formed?

        struct A { operator int(); } a;
        void foo() {
          typedef int T;
          a.operator T(); // 1) error T is not found in the context
    		      // of the class of the object expression?
        }

The second bullet in paragraph 1 of 3.4.3.1 [class.qual] says,

> a conversion-type-id of an operator-function-id is looked up both in the scope of the class and in the context in which the entire postfix-expression occurs and shall refer to the same type in both contexts

How about:

        struct A { typedef int T; operator T(); };
        struct B : A { operator T(); } b;
        void foo() {
          b.A::operator T(); // 2) error T is not found in the context
    			 // of the postfix-expression?
        }

Is this interpretation correct? Or was the intent for this to be an error only if `T` was found in both scopes and referred to different entities?

If the intent was for these to be errors, how do these rules apply to template arguments?

        template <class T1> struct A { operator T1(); }
        template <class T2> struct B : A<T2> {
          operator T2();
          void foo() {
    	T2 a = A<T2>::operator T2(); // 3) error? when instantiated T2 is not
    				     // found in the scope of the class
    	T2 b = ((A<T2>*)this)->operator T2(); // 4) error when instantiated?
          }
        }

(Note bullets 2 and 3 in paragraph 1 of 3.4.3.1 [class.qual] refer to postfix-expression. It would be better to use qualified-id in both cases.)

Erwin Unruh: The intent was that you look in both contexts. If you find it only once, that's the symbol. If you find it in both, both symbols must be "the same" in some respect. (If you don't find it, its an error).

Mike Miller: What's not clear to me in these examples is whether what is being looked up is `T` or `int`. Clearly the `T` has to be looked up somehow, but the "name" of a conversion function clearly involves the base (non-typedefed) type, not typedefs that might be used in a definition or reference (cf 3 [basic] paragraph 7 and 12.3 [class.conv] paragraph 5). (This is true even for types that must be written using typedefs because of the limited syntax in conversion-type-ids — e.g., the "name" of the conversion function in the following example

        typedef void (*pf)();
        struct S {
    	operator pf();
        };

is `S::operator void(*)()`, even though you can't write its name directly.)

My guess is that this means that in each scope you look up the type named in the reference and form the canonical operator name; if the name used in the reference isn't found in one or the other scope, the canonical name constructed from the other scope is used. These names must be identical, and the conversion-type-id in the canonical operator name must not denote different types in the two scopes (i.e., the type might not be found in one or the other scope, but if it's found in both, they must be the same type).

I think this is all very vague in the current wording.

#### 682. Missing description of lookup of template aliases

Section: 3.4.5 [basic.lookup.classref] Status: drafting Submitter: Daveed Vandevoorde Date: 1 March, 2008

3.4.5 [basic.lookup.classref] does not mention template aliases as the possible result of the lookup but should do so.

#### 1089. Template parameters in member selections

Section: 3.4.5 [basic.lookup.classref] Status: drafting Submitter: Daveed Vandevoorde Date: 2010-06-29

In an example like

        template<typename T> void f(T p)->decltype(p.T::x);

The nested-name-specifier `T::` looks like it refers to the template parameter. However, if this is instantiated with a type like

        struct T { int x; };
        struct S: T { };

the reference will be ambiguous, since it is looked up in both the context of the expression, finding the template parameter, and in the class, finding the base class injected-class-name, and this could be a deduction failure. As a result, the same declaration with a different parameter name

        template<typename U> void f(U p)->decltype(p.U::x);

is, in fact, not a redeclaration because the two can be distinguished by SFINAE.

It would be better to add a new lookup rule that says that if a name in a template definition resolves to a template parameter, that name is not subject to further lookup at instantiation time.

#### 1291. Looking up a conversion-type-id

Section: 3.4.5 [basic.lookup.classref] Status: drafting Submitter: Daveed Vandevoorde Date: 2011-04-10

The Standard talks about looking up a conversion-type-id as if it were an identifier (3.4.5 [basic.lookup.classref] paragraph 7), but that is not exactly accurate. Presumably it should talk instead about looking up names (if any) appearing in the type-specifier-seq of the conversion-type-id.

#### 426. Identically-named variables, one internally and one externally linked, allowed?

Section: 3.5 [basic.link] Status: drafting Submitter: Steve Adamczyk Date: 2 July 2003

An example in 3.5 [basic.link] paragraph 6 creates two file-scope variables with the same name, one with internal linkage and one with external.

      static void f();
      static int i = 0;                       //1
      void g() {
              extern void f();                // internal linkage
              int i;                          //2: i has no linkage
              {
                      extern void f();        // internal linkage
                      extern int i;           //3: external linkage
              }
      }

Is this really what we want? C99 has 6.2.2.7/7, which gives undefined behavior for having an identifier appear with internal and external linkage in the same translation unit. C++ doesn't seem to have an equivalent.

Notes from October 2003 meeting:

We agree that this is an error. We propose to leave the example but change the comment to indicate that line //3 has undefined behavior, and elsewhere add a normative rule giving such a case undefined behavior.

Proposed resolution (October, 2005):

Change 3.5 [basic.link] paragraph 6 as indicated:

> ...Otherwise, if no matching entity is found, the block scope entity receives external linkage. If, within a translation unit, the same entity is declared with both internal and external linkage, the behavior is undefined.

> [Example:

>         static void f();
>         static int i = 0;            // 1
>         void g () {
>             extern void f ();        // internal linkage
>             int i;                   // 2: i has no linkage
>             {
>                 extern void f ();    // internal linkage
>                 extern int i;        // 3: external linkage
>             }
>         }

> There are three objects named `i` in this program. The object with internal linkage introduced by the declaration in global scope (line `//1` ), the object with automatic storage duration and no linkage introduced by the declaration on line `//2`, and the object with static storage duration and external linkage introduced by the declaration on line `//3`. Without the declaration at line `//2`, the declaration at line `//3` would link with the declaration at line `//1`. But because the declaration with internal linkage is hidden, `//3` is given external linkage, resulting in a linkage conflict. —end example]

Notes frum the April 2006 meeting:

According to 3.5 [basic.link] paragraph 9, the two variables with linkage in the proposed example are not “the same entity” because they do not have the same linkage. Some other formulation will be needed to describe the relationship between those two variables.

Notes from the October 2006 meeting:

The CWG decided that it would be better to make a program with this kind of linkage mismatch ill-formed instead of having undefined behavior.

#### 1294. Side effects in dynamic/static initialization

Section: 3.6.2 [basic.start.init] Status: drafting Submitter: Daniel Krügler Date: 2011-04-08

According to 3.6.2 [basic.start.init] paragraph 3,

> An implementation is permitted to perform the initialization of a non-local variable with static storage duration as a static initialization even if such initialization is not required to be done statically, provided that

> - the dynamic version of the initialization does not change the value of any other object of namespace scope prior to its initialization, and

> - the static version of the initialization produces the same value in the initialized variable as would be produced by the dynamic initialization if all variables not required to be initialized statically were initialized dynamically.

This does not consider side effects of the initialization in this determination, only the values of namespace-scope variables.

#### 1027. Type consistency and reallocation of scalar types

Section: 3.8 [basic.life] Status: drafting Submitter: Gabriel Dos Reis Date: 2010-02-03

Is the following well-formed?

        int f() {
            int i = 3;
            new (&i) float(1.2);
            return i;
        }

The wording that is intended to prevent such shenanigans, 3.8 [basic.life] paragraphs 7-9, doesn't quite apply here. In particular, paragraph 7 reads,

> If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

> - the storage for the new object exactly overlays the storage location which the original object occupied, and

> - the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and...

The problem here is that this wording only applies “after the lifetime of an object has ended and before the storage which the object occupied is reused;” for an object of a scalar type, its lifetime only ends when the storage is reused or released (paragraph 1), so it appears that these restrictions cannot apply to such objects.

(See also issues 1116 and 1338.)

Proposed resolution (August, 2010):

This issue is resolved by the resolution of issue 1116.

#### 1116. Aliasing of union members

Section: 3.8 [basic.life] Status: drafting Submitter: US Date: 2010-08-02
N3092 comment US 27

Related to issue 1027, consider:

        int f() {
          union U { double d; } u1, u2;
          (int&)u1.d = 1;
          u2 = u1;
          return (int&)u2.d;
        }

Does this involve undefined behavior? 3.8 [basic.life] paragraph 4 seems to say that it's OK to clobber `u1` with an `int` object. Then union assignment copies the object representation, possibly creating an `int` object in `u2` and making the return statement well-defined. If this is well-defined, compilers are significantly limited in the assumptions they can make about type aliasing. On the other hand, the variant where `U` has an array of `unsigned char` member must be well-defined in order to support `std::aligned_storage`.

Suggested resolution: Clarify that this case is undefined, but that adding an array of `unsigned char` to union `U` would make it well-defined — if a storage location is allocated with a particular type, it should be undefined to create an object in that storage if it would be undefined to access the stored value of the object through the allocated type.

(See also issues 1027 and 1338.)

Proposed resolution (August, 2010):

1. Change 3.8 [basic.life] paragraph 1 as follows:

> ...The lifetime of an object of type `T` begins when storage with the proper alignment and size for type `T` is obtained, and either:

> - storage with the proper alignment and size for type `T` is obtained, and

> - if the object has non-trivial initialization, its initialization is complete., or

> - if `T` is trivially copyable, the object representation of another `T` object is copied into the storage.

> The lifetime of an object of type `T` ends...

2. Change 3.8 [basic.life] paragraph 4 as follows:

> A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5 [expr.delete]) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior. If a program obtains storage for an object of a particular type `A` (e.g. with a variable definition or new-expression) and later reuses that storage for an object of another type `B` such that accessing the stored value of the `B` object through a glvalue of type `A` would have undefined behavior (3.10 [basic.lval]), the behavior is undefined. [Example:

>       int i;
>       (double&)i = 1.0; // undefined behavior

>       struct S { unsigned char alignas(double) ar[sizeof (double)]; } s;
>       (double&)s = 1.0; // OK, can access stored double through s because it has an unsigned char subobject

> —end example]

3. Change 3.10 [basic.lval] paragraph 10 as follows:

> If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined52:

> - the dynamic type of the object,

> - a cv-qualified version of the dynamic type of the object,

> - a type similar (as defined in 4.4 [conv.qual]) to the dynamic type of the object,

> - a type that is the signed or unsigned type corresponding to the dynamic type of the object,

> - a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,

> - a `char` or `unsigned char` type,

> - an aggregate or union type that includes one of the aforementioned types among its elements, bases, or non-static data members (including, recursively, an element, base, or non-static data member of a subaggregate, base, or contained union),.

> - a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,

> - a `char` or `unsigned char` type.

This resolution also resolves issue 1027.

Additional note (August, 2012):

Concerns have been raised regarding the interaction of this change with facilities like `std::aligned_storage` and memory pools. Care must be taken to achieve the proper balance between supporting type-based optimization techniques and allowing practical storage management.

#### 1284. Should the lifetime of an array be independent of that of its elements?

Section: 3.8 [basic.life] Status: drafting Submitter: Gabriel Dos Reis Date: 2011-04-02

The note in 3.8 [basic.life] paragraph 2 reads,

> [Note: The lifetime of an array object starts as soon as storage with proper size and alignment is obtained, and its lifetime ends when the storage which the array occupies is reused or released. 12.6.2 [class.base.init] describes the lifetime of base and member subobjects. —end note]

This wording reflects an earlier version of paragraph 1 that deferred the start of an object's lifetime only for initialization of objects of class type. The note simply emphasized the implication that that the lifetime of a POD type or an array began immediately, even if lifetime of an array's elements began later.

The decomposition of POD types removed the mention of PODs, leaving only the array types, and when the normative text was changed to include aggregates whose members have non-trivial initialization, the note was overlooked.

It is not clear whether it would be better to update the note to emphasize the distinction between aggregates with non-trivial initialization and those without or to delete it entirely.

A possible related normative change to consider is whether the specification of paragraph 1 is sufficiently clear with respect to multidimensional arrays. The current definition of “non-trivial initialization” is:

> An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor.

Presumably the top-level array of an N-dimensional array whose ultimate element type is a class type with non-trivial initialization would also have non-trivial initialization, but it's not clear that this wording says that.

A more radical change that came up in the discussion was whether the undefined behavior resulting from an lvalue-to-rvalue conversion of an uninitialized object in 4.1 [conv.lval] paragraph 1 would be better dealt with as a lifetime violation instead.

#### 1530. Member access in out-of-lifetime objects

Section: 3.8 [basic.life] Status: drafting Submitter: Howard Hinnant Date: 2012-07-26

According to 3.8 [basic.life] paragraphs 5 and 6, a program has undefined behavior if a pointer or glvalue designating an out-of-lifetime object

> is used to access a non-static data member or call a non-static member function of the object

It is not clear what the word “access” means in this context. A reasonable interpretation might be using the pointer or glvalue as the left operand of a class member access expression; alternatively, it might mean to read or write the value of that member, allowing a class member access expression that is used only to form an address or bind a reference.

This needs to be clarified. A relevant consideration is the recent adoption of the resolution of issue 597, which eased the former restriction on simple address manipulations involving out-of-lifetime objects: if base-class offset calculations are now allowed, why not non-static data member offset calculations?

(See also issue 1531 for other uses of the term “access.”)

#### 1361. Requirement on brace-or-equal-initializers of literal types

Section: 3.9 [basic.types] Status: drafting Submitter: Richard Smith Date: 2011-08-16

The requirement in 3.8 [basic.life] paragraph 10 that

- every constructor call and full-expression in the brace-or-equal-initializers for non-static data members (if any) is a constant expression (5.19 [expr.const]),

is mostly redundant with the `constexpr` constructor requirements in 7.1.5 [dcl.constexpr] paragraph 4 (although 12.6.2 [class.base.init] does not establish a strict equivalence between brace-or-equal-initializers and mem-initializers).

#### 636. Dynamic type of objects and aliasing

Section: 3.10 [basic.lval] Status: drafting Submitter: Gabriel Dos Reis Date: 23 May 2007

The aliasing rules given in 3.10 [basic.lval] paragraph 10 rely on the concept of “dynamic type.” The problem is that the dynamic type of an object often cannot be determined (or even sufficiently constrained) at the point at which an optimizer needs to be able to determine whether aliasing might occur or not. For example, consider the function

        void foo(int* p, double* q) {
            *p = 42;
            *q = 3.14;
        }

An optimizer, on the basis of the existing aliasing rules, might decide that an `int*` and a `double*` cannot refer to the same object and reorder the assignments. This reordering, however, could result in undefined behavior if the function `foo` is called as follows:

       void goo() {
          union {
             int i;
             double d;
          } t;

          t.i = 12;

          foo(&t.i, &t.d);

          cout << t.d << endl;
       };

Here, the reference to `t.d` after the call to `foo` will be valid only if the assignments in `foo` are executed in the order in which they were written; otherwise, the union will contain an `int` object rather than a `double`.

One possibility would be to require that if such aliasing occurs, it be done only via member names and not via pointers.

Notes from the July, 2007 meeting:

This is the same issue as C's DR236. The CWG expressed a desire to address the issue the same way C99 does. The issue also occurs in C++ when placement new is used to end the lifetime of one object and start the lifetime of a different object occupying the same storage.

#### 1211. Misaligned lvalues

Section: 3.11 [basic.align] Status: drafting Submitter: David Svoboda Date: 2010-10-20

3.11 [basic.align] speaks of “alignment requirements,” and 3.7.4.1 [basic.stc.dynamic.allocation] requires the result of an allocation function to point to “suitably aligned” storage, but there is no explicit statement of what happens when these requirements are violated (presumably undefined behavior).

#### 617. Lvalue-to-rvalue conversions of uninitialized `char` objects

Section: 4.1 [conv.lval] Status: drafting Submitter: Alan Stokes Date: 6 February 2007

According to 4.1 [conv.lval] paragraph 1, applying the lvalue-to-rvalue conversion to any uninitialized object results in undefined behavior. However, character types are intended to allow any data, including uninitialized objects and padding, to be copied (hence the statements in 3.9.1 [basic.fundamental] paragraph 1 that “For character types, all bits of the object representation participate in the value representation” and in 3.10 [basic.lval] paragraph 15 that `char` and `unsigned char` types can alias any object). The lvalue-to-rvalue conversion should be permitted on uninitialized objects of character type without evoking undefined behavior.

#### 170. Pointer-to-member conversions

Section: 4.11 [conv.mem] Status: drafting Submitter: Mike Stump Date: 16 Sep 1999

The descriptions of explicit (5.2.9 [expr.static.cast] paragraph 9) and implicit (4.11 [conv.mem] paragraph 2) pointer-to-member conversions differ in two significant ways:

1. In a `static_cast`, a conversion in which the class in the target pointer-to-member type is a base of the class in which the member is declared is permitted and required to work correctly, as long as the resulting pointer-to-member is eventually dereferenced with an object whose dynamic type contains the member. That is, the class of the target pointer-to-member type is not required to contain the member referred to by the value being converted. The specification of implicit pointer-to-member conversion is silent on this question.

   (This situation cannot arise in an implicit pointer-to-member conversion where the source value is something like `&X::f`, since you can only implicitly convert from pointer-to-base-member to pointer-to-derived-member. However, if the source value is the result of an explicit "up-cast," the target type of the conversion might still not contain the member referred to by the source value.)

2. The target type in a `static_cast` is allowed to be more cv-qualified than the source type; in an implicit conversion, however, the cv-qualifications of the two types are required to be identical.

The first difference seems like an oversight. It is not clear whether the latter difference is intentional or not.

(See also issue 794.)

#### 536. Problems in the description of id-expressions

Section: 5.1.1 [expr.prim.general] Status: drafting Submitter: Mike Miller Date: 13 October 2005

There are at least a couple of problems in the description of the various id-expressions in 5.1.1 [expr.prim.general]:

1. Paragraph 4 embodies an incorrect assumption about the syntax of qualified-ids:

   > The operator `::` followed by an identifier, a qualified-id, or an operator-function-id is a primary-expression.

   The problem here is that the `::` is actually part of the syntax of qualified-id; consequently, “`::` followed by... a qualified-id” could be something like “`:: ::i`,” which is ill-formed. Presumably this should say something like, “A qualified-id with no nested-name-specifier is a primary-expression.”

2. More importantly, some kinds of id-expressions are not described by 5.1.1 [expr.prim.general]. The structure of this section is that the result, type, and lvalue-ness are specified for each of the cases it covers:

   - paragraph 4 deals with qualified-ids that have no nested-name-specifier

   - paragraph 7 deals with bare identifiers and with qualified-ids containing a nested-name-specifier that names a class

   - paragraph 8 deals with qualified-ids containing a nested-name-specifier that names a namespace

   This treatment leaves unspecified all the non-identifier unqualified-ids (operator-function-id, conversion-function-id, and template-id), as well as (perhaps) “`::` template-id” (it's not clear whether the “`::` followed by a qualified-id” case is supposed to apply to template-ids or not). Note also that the proposed resolution of issue 301 slightly exacerbates this problem by removing the form of operator-function-id that contains a tmeplate-argument-list; as a result, references like “`::operator+<X>`” are no longer covered in 5.1.1 [expr.prim.general].

#### 1249. Cv-qualification of nested lambda capture

Section: 5.1.2 [expr.prim.lambda] Status: drafting Submitter: James Widman Date: 2011-03-02

Consider the following example:

        void f(int i) {
          auto l1 = [i] {
            auto l2 = [&i] {
              ++i;    // Well-formed?
            };
          };
        }

Because the `l1` lambda is not marked as `mutable`, its `operator()` is `const`; however, it is not clear from the wording of 5.1.2 [expr.prim.lambda] paragraph 16 whether the captured member of the enclosing lambda is considered `const` or not.

#### 1468. `typeid`, overload resolution, and implicit lambda capture

Section: 5.1.2 [expr.prim.lambda] Status: drafting Submitter: Doug Gregor Date: 2012-02-08

According to 5.1.2 [expr.prim.lambda] paragraph 11, a variable is implicitly captured if it is odr-used. In the following example,

      struct P {
       virtual ~P();
      };

      P &f(int&);
      int f(const int&);

      void g(int x) {
       [=] {
        typeid(f(x));
       };
      }

`x` is only odr-used if the operand of `typeid` is a polymorphic lvalue; otherwise, the operand is unevaluated (5.2.8 [expr.typeid] paragraphs 2-3). Whether the operand is a polymorphic lvalue depends on overload resolution in this case, which depends on whether `x` is captured or not: if `x` is captured, since the lambda is not `mutable`, the type of `x` in the body of the lambda is `const int`, while if it is not captured, it is just `int`. However, the `const int` version of `f` returns `int` and the `int` version of `f` returns a polymorphic lvalue, leading to a conundrum: `x` is only captured if it is not captured, and vice versa.

Notes from the October, 2012 meeting:

The approach favored by CWG was to specify that the operand of `typeid` is considered to be odr-used for the purpose of determining capture.

#### 1213. Array subscripting and xvalues

Section: 5.2.1 [expr.sub] Status: drafting Submitter: Jason Merrill Date: 2010-10-24

Because the subscripting operation is defined as indirection through a pointer value, the result of a subscript operator applied to an xvalue array is an lvalue, not an xvalue. This could be surprising to some.

#### 1521. `T{`expr`}` with reference types

Section: 5.2.3 [expr.type.conv] Status: drafting Submitter: Steve Adamczyk Date: 2012-07-10

According to 5.2.3 [expr.type.conv] paragraph 4,

> Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4 [dcl.init.list]) with the specified braced-init-list, and its value is that temporary object as a prvalue.

This wording does not handle the case where `T` is a reference type: it is not possible to create a temporary object of that type, and presumably the result would be an xvalue, not a prvalue.

#### 1376. `static_cast` of temporary to rvalue reference

Section: 5.2.9 [expr.static.cast] Status: drafting Submitter: Michael Wong Date: 2011-08-17

In a declaration like

        T&& r = static_cast<T&&>(T());

it is not clear what the lifetime of the `T` temporary should be. According to 5.2.9 [expr.static.cast] paragraph 4, the `static_cast` is equivalent to a declaration of an invented temporary variable `t`. The lifetime of the temporary is extended to that of `t`, but it is not clear what that lifetime should be, nor if the subsequent binding of `t` to `r` would affect the lifetime of the original temporary.

Notes from the February, 2012 meeting:

The reference is bound to the xvalue result of the `static_cast`, so the lifetime of the temporary is not extended and this example results in a dangling reference.

Proposed resolution (February, 2012):

Change 5.2.9 [expr.static.cast] paragraph 4 as follows:

> Otherwise, an expression `e` can be explicitly converted to a type `T` using a `static_cast` of the form `static_cast<T>(e)` if the declaration `T t(e);` is well-formed, for some invented temporary variable `t` (8.5 [dcl.init]). The effect...

#### 232. Is indirection through a null pointer undefined behavior?

Section: 5.3.1 [expr.unary.op] Status: drafting Submitter: Mike Miller Date: 5 Jun 2000

At least a couple of places in the IS state that indirection through a null pointer produces undefined behavior: 1.9 [intro.execution] paragraph 4 gives "dereferencing the null pointer" as an example of undefined behavior, and 8.3.2 [dcl.ref] paragraph 4 (in a note) uses this supposedly undefined behavior as justification for the nonexistence of "null references."

However, 5.3.1 [expr.unary.op] paragraph 1, which describes the unary "*" operator, does not say that the behavior is undefined if the operand is a null pointer, as one might expect. Furthermore, at least one passage gives dereferencing a null pointer well-defined behavior: 5.2.8 [expr.typeid] paragraph 2 says

> If the lvalue expression is obtained by applying the unary * operator to a pointer and the pointer is a null pointer value (4.10 [conv.ptr]), the `typeid` expression throws the `bad_typeid` exception (18.7.3 [bad.typeid]).

This is inconsistent and should be cleaned up.

Bill Gibbons:

At one point we agreed that dereferencing a null pointer was not undefined; only using the resulting value had undefined behavior.

For example:

        char *p = 0;
        char *q = &*p;

Similarly, dereferencing a pointer to the end of an array should be allowed as long as the value is not used:

        char a[10];
        char *b = &a[10];   // equivalent to "char *b = &*(a+10);"

Both cases come up often enough in real code that they should be allowed.

Mike Miller:

I can see the value in this, but it doesn't seem to be well reflected in the wording of the Standard. For instance, presumably `*p` above would have to be an lvalue in order to be the operand of "`&`", but the definition of "lvalue" in 3.10 [basic.lval] paragraph 2 says that "an lvalue refers to an object." What's the object in `*p`? If we were to allow this, we would need to augment the definition to include the result of dereferencing null and one-past-the-end-of-array.

Tom Plum:

Just to add one more recollection of the intent: I was very happy when (I thought) we decided that it was only the attempt to actually fetch a value that creates undefined behavior. The words which (I thought) were intended to clarify that are the first three sentences of the lvalue-to-rvalue conversion, 4.1 [conv.lval]:

> An lvalue (3.10 [basic.lval]) of a non-function, non-array type `T` can be converted to an rvalue. If `T` is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the lvalue refers is not an object of type `T` and is not an object of a type derived from `T`, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior.

In other words, it is only the act of "fetching", of lvalue-to-rvalue conversion, that triggers the ill-formed or undefined behavior. Simply forming the lvalue expression, and then for example taking its address, does not trigger either of those errors. I described this approach to WG14 and it may have been incorporated into C 1999.

Mike Miller:

If we admit the possibility of null lvalues, as Tom is suggesting here, that significantly undercuts the rationale for prohibiting "null references" -- what is a reference, after all, but a named lvalue? If it's okay to create a null lvalue, as long as I don't invoke the lvalue-to-rvalue conversion on it, why shouldn't I be able to capture that null lvalue as a reference, with the same restrictions on its use?

I am not arguing in favor of null references. I don't want them in the language. What I am saying is that we need to think carefully about adopting the permissive approach of saying that it's all right to create null lvalues, as long as you don't use them in certain ways. If we do that, it will be very natural for people to question why they can't pass such an lvalue to a function, as long as the function doesn't do anything that is not permitted on a null lvalue.

If we want to allow `&*(p=0)`, maybe we should change the definition of "`&`" to handle dereferenced null specially, just as `typeid` has special handling, rather than changing the definition of lvalue to include dereferenced nulls, and similarly for the array_end+1 case. It's not as general, but I think it might cause us fewer problems in the long run.

Notes from the October 2003 meeting:

See also issue 315, which deals with the call of a static member function through a null pointer.

We agreed that the approach in the standard seems okay: `p = 0; *p;` is not inherently an error. An lvalue-to-rvalue conversion would give it undefined behavior.

Proposed resolution (October, 2004):

(Note: the resolution of issue 453 also resolves part of this issue.)

1. Add the indicated words to 3.10 [basic.lval] paragraph 2:

   > An lvalue refers to an object or function or is an empty lvalue (5.3.1 [expr.unary.op]).

2. Add the indicated words to 5.3.1 [expr.unary.op] paragraph 1:

   > The unary `*` operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points, if any. If the pointer is a null pointer value (4.10 [conv.ptr]) or points one past the last element of an array object (5.7 [expr.add]), the result is an empty lvalue and does not refer to any object or function. An empty lvalue is not modifiable. If the type of the expression is “pointer to `T`,” the type of the result is “`T`.” [Note: a pointer to an incomplete type (other than cv void) can be dereferenced. The lvalue thus obtained can be used in limited ways (to initialize a reference, for example); this lvalue must not be converted to an rvalue, see 4.1 [conv.lval].—end note]

3. Add the indicated words to 4.1 [conv.lval] paragraph 1:

   > If the object to which the lvalue refers is not an object of type `T` and is not an object of a type derived from `T`, or if the object is uninitialized, or if the lvalue is an empty lvalue (5.3.1 [expr.unary.op]), a program that necessitates this conversion has undefined behavior.

4. Change 1.9 [intro.execution] as indicated:

   > Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer division by zero).

Note (March, 2005):

The 10/2004 resolution interacts with the resolution of issue 73. We added wording to 3.9.2 [basic.compound] paragraph 3 to the effect that a pointer containing the address one past the end of an array is considered to “point to” another object of the same type that might be located there. The 10/2004 resolution now says that it would be undefined behavior to use such a pointer to fetch the value of that object. There is at least the appearance of conflict here; it may be all right, but it at needs to be discussed further.

Notes from the April, 2005 meeting:

The CWG agreed that there is no contradiction between this direction and the resolution of issue 73. However, “not modifiable” is a compile-time concept, while in fact this deals with runtime values and thus should produce undefined behavior instead. Also, there are other contexts in which lvalues can occur, such as the left operand of `.` or `.*`, which should also be restricted. Additional drafting is required.

(See also issue 1102.)

#### 901. Deleted `operator delete`

Section: 5.3.4 [expr.new] Status: drafting Submitter: John Spicer Date: 20 May, 2009

It is not clear from 5.3.4 [expr.new] whether a deleted `operator delete` is referenced by a new-expression in which there is no initialization or in which the initialization cannot throw an exception, rendering the program ill-formed. (The question also arises as to whether such a new-expression constitutes a “use” of the deallocation function in the sense of 3.2 [basic.def.odr].)

Notes from the July, 2009 meeting:

The rationale for defining a deallocation function as deleted would presumably be to prevent such objects from being freed. Treating the new-expression as a use of such a deallocation function would mean that such objects could not be created in the first place. There is already an exemption from freeing an object if “a suitable deallocation function [cannot] be found;” a deleted deallocation function should be treated similarly.

#### 1469. Omitted bound in array new-expression

Section: 5.3.4 [expr.new] Status: drafting Submitter: Johannes Schaub Date: 2012-02-12

The syntax for noptr-new-declarator in 5.3.4 [expr.new] paragraph 1 requires an expression, even though the bound could be inferred from a braced-init-list initializer. It is not clear whether 8.5.1 [dcl.init.aggr] paragraph 4,

> An array of unknown size initialized with a brace-enclosed initializer-list containing `n` initializer-clauses, where `n` shall be greater than zero, is defined as having `n` elements (8.3.4 [dcl.array]).

should be considered to apply to the new-type-id variant, e.g.,

      new (int[]){1, 2, 3}

Additional note (August, 2012):

The consensus during the 2012-08-13 drafting review teleconference was that this issue should be referred to the Evolution Working Group and not handled by the Core Working Group.

#### 1566. Should `new std::initializer_list<T>` be ill-formed?

Section: 5.3.4 [expr.new] Status: drafting Submitter: Steve Adamczyk Date: 2012-10-10

A new-expression that creates an object whose type is a specialization of `std::initializer_list` initialized from an initializer list results in undefined behavior if the object survives past the end of the full-expression, when the lifetime of the underlying array object ends. Since such a new-expression is effectively useless, should it be made ill-formed?

Notes from the October, 2012 meeting:

The consensus of CWG was that this usage should be ill-formed.

#### 1542. Compound assignment of braced-init-list

Section: 5.17 [expr.ass] Status: drafting Submitter: Mike Miller Date: 2012-08-21

The specification of 5.17 [expr.ass] paragraph 9 is presumably intended to allow use of a braced-init-list as the operand of a compound assignment operator as well as a simple assignment operator, although the normative wording does not explicitly say so. (The example in that paragraph does include

      complex<double> z;
      z += { 1, 2 };      // meaning z.operator+=({1,2})

for instance, which could be read to imply compound assignment operators for scalar types as well.)

However, the details of how this is to be implemented are not clear. Paragraph 7 says,

> The behavior of an expression of the form `E1` op `=` `E2` is equivalent to `E1 = E1` op `E2` except that `E1` is evaluated only once.

Applying this pattern literally to a braced-init-list yields invalid code: `x += {1}` would become `x = x + {1}`, which is non-syntactic.

Another problem is how to apply the prohibition against narrowing conversions to a compound assignment. For example,

      char c;
      c += {1};

would presumably always be a narrowing error, because after integral promotions, the type of `c+1` is `int`. The similar issue 1078 was classified as "NAD" because the workaround was simply to add a cast to suppress the error; however, there is no place to put a similar cast in a compound assignment.

Notes from the October, 2012 meeting:

The incorrect description of the meaning of a compound assignment with a braced-init-list should be fixed by CWG. The question of whether it makes sense to apply narrowing rules to such assignments is better addressed by EWG.

#### 1255. Definition problems with `constexpr` functions

Section: 5.19 [expr.const] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-08

The current wording of the Standard is not sufficiently clear regarding the interaction of class scope (which treats the bodies of member functions as effectively appearing after the class definition is complete) and the use of `constexpr` member functions within the class definition in contexts requiring constant expressions. For example, an array bound cannot use a `constexpr` member function that relies on the completeness of the class or on members that have not yet been declared, but the current wording does not appear to state that.

#### 1452. Value-initialized objects may be constants

Section: 5.19 [expr.const] Status: drafting Submitter: Richard Smith Date: 2011-12-24

Some classes that would produce a constant when initialized by value-initialization are not considered literal types. For example:

       struct A { int a; }; // non-constexpr default constructor
       struct B : A {};     // non-literal type

#### 1480. Constant initialization via non-constant temporary

Section: 5.19 [expr.const] Status: drafting Submitter: Daniel Krügler Date: 2012-03-17

The following initializations appear to be well-formed:

      struct C {
       int m;
       constexpr C(int m ) : m{m} {};
       constexpr int get() { return m; };
      };

      C&& rr = C{1};
      constexpr int k1 = rr.get();

      const C& cl = C{1};
      constexpr int k2 = cl.get();

They appear to fall under the bullet of 5.19 [expr.const] paragraph 2,

- an lvalue-to-rvalue conversion (4.1 [conv.lval]) unless it is applied to

- ...

- a non-volatile glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;

The problem in this example is that the referenced temporary object is not a constant, so it would be well-defined for intervening code to modify its value before it was used in the later initialization.

#### 1274. Common nonterminal for expression and braced-init-list

Section: 6.5.4 [stmt.ranged] Status: drafting Submitter: Daniel Krügler Date: 2011-03-25

It would be helpful to have a single grammar term for expression and braced-init-list, which often occur together in the text. In particular, 6.5.4 [stmt.ranged] paragraph 1 allows both, but the description of `__RangeT` refers only to the expression case; such errors would be less likely if the common term were available.

#### 1223. Syntactic disambiguation and trailing-return-types

Section: 6.8 [stmt.ambig] Status: drafting Submitter: Michael Wong Date: 2010-11-08

Because the restriction that a trailing-return-type can appear only in a declaration with “the single type-specifier `auto`” (8.3.5 [dcl.fct] paragraph 2) is a semantic, not a syntactic, restriction, it does not influence disambiguation, which is “purely syntactic” (6.8 [stmt.ambig] paragraph 3). Consequently, some previously unambiguous expressions are now ambiguous. For example:

    struct A {
      A(int *);
      A *operator()(void);
      int B;
    };

    int *p;
    typedef struct BB { int C[2]; } *B, C;

    void foo() {
    // The following line becomes invalid under C++0x:
      A (p)()->B;  // ill-formed function declaration

    // In the following,
    // - B()->C is either type-id or class member access expression
    // - B()->C[1] is either type-id or subscripting expression
    // N3126 subclause 8.2 [dcl.ambig.res] does not mention an ambiguity
    // with these forms of expression
      A a(B ()->C);  // function declaration or object declaration
      sizeof(B ()->C[1]);  // sizeof(type-id) or sizeof on an expression
    }

Notes from the March, 2011 meeting:

CWG agreed that the presence of `auto` should be considered in disambiguation, even though it is formally handled semantically rather than syntactically.

#### 1325. Omitted declarator in `friend` declarations

Section: 7 [dcl.dcl] Status: drafting Submitter: Johannes Schaub Date: 2011-05-27

According to 7 [dcl.dcl] paragraph 3,

> In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9 [class]) or enumeration (7.2 [dcl.enum]), that is, when the decl-specifier-seq contains either a class-specifier, an elaborated-type-specifier with a class-key (9.1 [class.name]), or an enum-specifier.

This does not allow for the new simplified `friend` declaration syntax (11.3 [class.friend] paragraph 3), which permits the forms

`friend` simple-type-specifier `;`
`friend` typename-specifier `;`

#### 1247. Restriction on alias name appearing in type-id

Section: 7.1.3 [dcl.typedef] Status: drafting Submitter: James Widman Date: 2011-02-26

With the resolution of issue 1044, there is no need to say that the name of the alias cannot appear in the type-id of the declaration.

#### 1348. Use of `auto` in a trailing-return-type

Section: 7.1.6.4 [dcl.spec.auto] Status: drafting Submitter: Richard Smith Date: 2011-08-16

It is not clear whether the `auto` specifier can appear in a trailing-return-type.

#### 1485. Out-of-class definition of member unscoped opaque enumeration

Section: 7.2 [dcl.enum] Status: drafting Submitter: Richard Smith Date: 2012-03-26

The scope in which the names of enumerators are entered for a member unscoped opaque enumeration is not clear. According to 7.2 [dcl.enum] paragraph 10,

> Each enum-name and each unscoped enumerator is declared in the scope that immediately contains the enum-specifier.

In the case of a member opaque enumeration defined outside its containing class, however, it is not clear whether the enumerator names are declared in the class scope or in the lexical scope containing the definition. Declaring them in the class scope would be a violation of 9.2 [class.mem] paragraph 1:

> The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere.

Declaring the names in the lexical scope containing the definition would be contrary to the example in 14.5.1.4 [temp.mem.enum] paragraph 1:

      template<class T> struct A {
        enum E : T;
      };
      A<int> a;
      template<class T> enum A<T>::E : T { e1, e2 };
      A<int>::E e = A<int>::e1;

There also appear to be problems with the rules for dependent types and members of the current instantiation.

#### 138. Friend declaration name lookup

Section: 7.3.1.2 [namespace.memdef] Status: drafting Submitter: Martin von Loewis Date: 14 Jul 1999

7.3.1.2 [namespace.memdef] paragraph 3 says,

> If a `friend` declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace... When looking for a prior declaration of a class or a function declared as a `friend`, scopes outside the innermost enclosing namespace scope are not considered.

It is not clear from this passage how to determine whether an entity is "first declared" in a `friend` declaration. One question is whether a using-declaration influences this determination. For instance:

        void foo();
        namespace A{
          using ::foo;
          class X{
    	friend void foo();
          };
        }

Is the `friend` declaration a reference to `::foo` or a different `foo`?

Part of the question involves determining the meaning of the word "synonym" in 7.3.3 [namespace.udecl] paragraph 1:

> A using-declaration introduces a name into the declarative region in which the using-declaration appears. That name is a synonym for the name of some entity declared elsewhere.

Is "`using ::foo;`" the declaration of a function or not?

More generally, the question is how to describe the lookup of the name in a `friend` declaration.

John Spicer: When a declaration specifies an unqualified name, that name is declared, not looked up. There is a mechanism in which that declaration is linked to a prior declaration, but that mechanism is not, in my opinion, via normal name lookup. So, the friend always declares a member of the nearest namespace scope regardless of how that name may or may not already be declared there.

Mike Miller: 3.4.1 [basic.lookup.unqual] paragraph 7 says:

> A name used in the definition of a class `X` outside of a member function body or nested class definition shall be declared in one of the following ways:... [Note: when looking for a prior declaration of a class or function introduced by a `friend` declaration, scopes outside of the innermost enclosing namespace scope are not considered.]

The presence of this note certainly implies that this paragraph describes the lookup of names in `friend` declarations.

John Spicer: It most certainly does not. If that section described the friend lookup it would yield the incorrect results for the friend declarations of `f` and `g` below. I don't know why that note is there, but it can't be taken to mean that that is how the friend lookup is done.

        void f(){}
        void g(){}
        class B {
            void g();
        };
        class A : public B {
            void f();
            friend void f(); // ::f not A::f
            friend void g(); // ::g not B::g
        };

Mike Miller: If so, the lookups for friend functions and classes behave differently. Consider the example in 3.4.4 [basic.lookup.elab] paragraph 3:

        struct Base {
            struct Data;         // OK: declares nested Data
            friend class Data;   // OK: nested Data is a friend
        };

If the `friend` declaration is not a reference to `::foo`, there is a related but separate question: does the `friend` declaration introduce a conflicting (albeit "invisible") declaration into namespace `A`, or is it simply a reference to an as-yet undeclared (and, in this instance, undeclarable) `A::foo`? Another part of the example in 3.4.4 [basic.lookup.elab] paragraph 3 is related:

        struct Data {
            friend struct Glob;  // OK: Refers to (as yet) undeclared Glob
                                 // at global scope.
        };

John Spicer: You can't refer to something that has not yet been declared. The friend is a declaration of `Glob`, it just happens to declare it in a such a way that its name cannot be used until it is redeclared.

(A somewhat similar question has been raised in connection with issue 36. Consider:

        namespace N {
            struct S { };
        }
        using N::S;
        struct S;          // legal?

According to 9.1 [class.name] paragraph 2,

> A declaration consisting solely of class-key identifier ; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name.

Should the elaborated type declaration in this example be considered a redeclaration of `N::S` or an invalid forward declaration of a different class?)

(See also issues 95, 136, 139, 143, 165, and 166, as well as paper J16/00-0006 = WG21 N1229.)

#### 386. Friend declaration of name brought in by using-declaration

Section: 7.3.3 [namespace.udecl] Status: drafting Submitter: Herb Sutter Date: 8 Oct 2002

The following came up recently on comp.lang.c++.moderated (edited for brevity):

      namespace N1 {
        template<typename T> void f( T* x ) {
          // ... other stuff ...
          delete x;
        }
      }

      namespace N2 {
        using N1::f;

        template<> void f<int>( int* ); // A: ill-formed

        class Test {
          ~Test() { }
          friend void f<>( Test* x );   // B: ill-formed?
        };
      }

I strongly suspect, but don't have standardese to prove, that the friend declaration in line B is ill-formed. Can someone show me the text that allows or disallows line B?

Here's my reasoning: Writing "using" to pull the name into namespace N2 merely allows code in N2 to use the name in a call without qualification (per 7.3.3 [namespace.udecl]). But just as declaring a specialization must be done in the namespace where the template really lives (hence line A is ill-formed), I suspect that declaring a specialization as a friend must likewise be done using the original namespace name, not obliquely through a "using". I see nothing in 7.3.3 [namespace.udecl] that would permit this use. Is there?

Andrey Tarasevich: 14.5.4 [temp.friend] paragraph 2 seems to get pretty close: "A friend declaration that is not a template declaration and in which the name of the friend is an unqualified 'template-id' shall refer to a specialization of a function template declared in the nearest enclosing namespace scope".

Herb Sutter: OK, thanks. Then the question in this is the word "declared" -- in particular, we already know we cannot declare a specialization of a template in any other namespace but the original one.

John Spicer: This seems like a simple question, but it isn't.

First of all, I don't think the standard comments on this usage one way or the other.

A similar example using a namespace qualified name is ill-formed based on 8.3 [dcl.meaning] paragraph 1:

      namespace N1 {
            void f();
      }

      namespace N2 {
            using N1::f;
            class A {
                    friend void N2::f();
            };
      }

Core issue 138 deals with this example:

      void foo();
      namespace A{
        using ::foo;
        class X{
          friend void foo();
        };
      }

The proposed resolution (not yet approved) for issue 138 is that the friend declares a new foo that conflicts with the using-declaration and results in an error.

Your example is different than this though because the presence of the explicit argument list means that this is not declaring a new f but is instead using a previously declared f.

One reservation I have about allowing the example is the desire to have consistent rules for all of the "declaration like" uses of template functions. Issue 275 (in DR status) addresses the issue of unqualified names in explicit instantiation and explicit specialization declarations. It requires that such declarations refer to templates from the namespace containing the explicit instantiation or explicit specialization. I believe this rule is necessary for those directives but is not really required for friend declarations -- but there is the consistency issue.

Notes from April 2003 meeting:

This is related to issue 138. John Spicer is supposed to update his paper on this topic. This is a new case not covered in that paper. We agreed that the B line should be allowed.

#### 1342. Order of initialization with multiple declarators

Section: 8 [dcl.decl] Status: drafting Submitter: Alberto Ganesh Barbati Date: 2011-08-11

It is not clear what, if anything, in the existing specification requires that the initialization of multiple init-declarators within a single declaration be performed in declaration order.

#### 1488. abstract-pack-declarators in type-ids

Section: 8.1 [dcl.name] Status: drafting Submitter: Richard Smith Date: 2012-03-28

The grammar for type-id in 9.1 [class.name] paragraph 1 has two problems. First, the fact that we allow an abstract-pack-declarator makes some uses of type-id (template arguments, alignment specifiers, exception-specifications) ambiguous: `T...` could be parsed either as a type-id, including the ellipsis, or as the type-id `T` with a following ellipsis. There does not appear to be any rule to disambiguate these parses.

The other problem is that we do not allow parentheses in an abstract-pack-declarator, which makes

      template<typename...Ts> void f(Ts (&...)[4]);

ill-formed because `(&...)()` is not an abstract-pack-declarator. There is implementation variance on this point.

#### 453. References may only bind to “valid” objects

Section: 8.3.2 [dcl.ref] Status: drafting Submitter: Gennaro Prota Date: 18 Jan 2004

8.3.2 [dcl.ref] paragraph 4 says:

> A reference shall be initialized to refer to a valid object or function. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior ...]

What is a "valid" object? In particular the expression "valid object" seems to exclude uninitialized objects, but the response to Core Issue 363 clearly says that's not the intent. This is an example (overloading construction on constness of *this) by John Potter, which I think is supposed to be legal C++ though it binds references to objects that are not initialized yet:

     struct Fun {
        int x, y;
        Fun (int x, Fun const&) : x(x), y(42) { }
        Fun (int x, Fun&) : x(x), y(0) { }
      };
      int main () {
        const Fun f1 (13, f1);
        Fun f2 (13, f2);
        cout << f1.y << " " << f2.y << "\n";
      }

Suggested resolution: Changing the final part of 8.3.2 [dcl.ref] paragraph 4 to:

> A reference shall be initialized to refer to an object or function. From its point of declaration on (see 3.3.2 [basic.scope.pdecl]) its name is an lvalue which refers to that object or function. The reference may be initialized to refer to an uninitialized object but, in that case, it is usable in limited ways (3.8 [basic.life], paragraph 6) [Note: On the other hand, a declaration like this:

>         int & ref = *(int*)0;

> is ill-formed because ref will not refer to any object or function ]

I also think a "No diagnostic is required." would better be added (what about something like int& r = r; ?)

Proposed Resolution (October, 2004):

(Note: the following wording depends on the proposed resolution for issue 232.)

Change 8.3.2 [dcl.ref] paragraph 4 as follows:

> A reference shall be initialized to refer to a valid object or function. If an lvalue to which a reference is directly bound designates neither an existing object or function of an appropriate type (8.5.3 [dcl.init.ref]), nor a region of memory of suitable size and alignment to contain an object of the reference's type (1.8 [intro.object], 3.8 [basic.life], 3.9 [basic.types]), the behavior is undefined. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” empty lvalue obtained by dereferencing a null pointer, which causes undefined behavior. As does not designate an object or function. Also, as described in 9.6 [class.bit], a reference cannot be bound directly to a bit-field. ]

> The name of a reference shall not be used in its own initializer. Any other use of a reference before it is initialized results in undefined behavior. [Example:

>       int& f(int&);
>       int& g();

>       extern int& ir3;
>       int* ip = 0;

>       int& ir1 = *ip;     // undefined behavior: null pointer
>       int& ir2 = f(ir3);  // undefined behavior: ir3 not yet initialized
>       int& ir3 = g();
>       int& ir4 = f(ir4);  // ill-formed: ir4 used in its own initializer

> —end example]

Rationale: The proposed wording goes beyond the specific concerns of the issue. It was noted that, while the current wording makes cases like `int& r = r;` ill-formed (because `r` in the initializer does not "refer to a valid object"), an inappropriate initialization can only be detected, if at all, at runtime and thus "undefined behavior" is a more appropriate treatment. Nevertheless, it was deemed desirable to continue to require a diagnostic for obvious compile-time cases.

It was also noted that the current Standard does not say anything about using a reference before it is initialized. It seemed reasonable to address both of these concerns in the same wording proposed to resolve this issue.

Notes from the April, 2005 meeting:

The CWG decided that whether to require an implementation to diagnose initialization of a reference to itself should be handled as a separate issue (504) and also suggested referring to “storage” instead of “memory” (because 1.8 [intro.object] defines an object as a “region of storage”).

Proposed Resolution (April, 2005):

(Note: the following wording depends on the proposed resolution for issue 232.)

Change 8.3.2 [dcl.ref] paragraph 4 as follows:

> A reference shall be initialized to refer to a valid object or function. If an lvalue to which a reference is directly bound designates neither an existing object or function of an appropriate type (8.5.3 [dcl.init.ref]), nor a region of storage of suitable size and alignment to contain an object of the reference's type (1.8 [intro.object], 3.8 [basic.life], 3.9 [basic.types]), the behavior is undefined. [Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” empty lvalue obtained by dereferencing a null pointer, which causes undefined behavior. As does not designate an object or function. Also, as described in 9.6 [class.bit], a reference cannot be bound directly to a bit-field. ]

> Any use of a reference before it is initialized results in undefined behavior. [Example:

>       int& f(int&);
>       int& g();

>       extern int& ir3;
>       int* ip = 0;

>       int& ir1 = *ip;     // undefined behavior: null pointer
>       int& ir2 = f(ir3);  // undefined behavior: ir3 not yet initialized
>       int& ir3 = g();
>       int& ir4 = f(ir4);  // undefined behavior: ir4 used in its own initializer

> —end example]

Note (February, 2006):

The word “use” in the last paragraph of the proposed resolution was intended to refer to the description in 3.2 [basic.def.odr] paragraph 2. However, that section does not define what it means for a reference to be “used,” dealing only with objects and functions. Additional drafting is required to extend 3.2 [basic.def.odr] paragraph 2 to apply to references.

Additional note (May, 2008):

The proposed resolution for issue 570 adds wording to define “use” for references.

Note, January, 2012:

The resolution should also probably deal with the fact that the “one-past-the-end” address of an array does not designate a valid object (even if such a pointer might “point to” an object of the correct type, per 3.9.2 [basic.compound]) and thus is not suuitable for the lvalue-to-rvalue conversion.

#### 393. Pointer to array of unknown bound in template argument list in parameter

Section: 8.3.5 [dcl.fct] Status: drafting Submitter: Mark Mitchell Date: 12 Dec 2002

EDG rejects this code:

      template <typename T>
      struct S {};

      void f (S<int (*)[]>);

G++ accepts it.

This is another case where the standard isn't very clear:

The language from 8.3.5 [dcl.fct] is:

> If the type of a parameter includes a type of the form "pointer to array of unknown bound of T" or "reference to array of unknown bound of T," the program is ill-formed.

Since "includes a type" is not a term defined in the standard, we're left to guess what this means. (It would be better if this were a recursive definition, the way a type theoretician would do it:

- Every type includes itself.
- T* includes T
- T[] includes T
- ...

)

Notes from April 2003 meeting:

We agreed that the example should be allowed.

#### 1001. Parameter type adjustment in dependent parameter types

Section: 8.3.5 [dcl.fct] Status: drafting Submitter: Jason Merrill Date: 2009-11-08

According to 8.3.5 [dcl.fct] paragraph 5, top-level cv-qualifiers on parameter types are deleted when determining the function type. It is not clear how or whether this adjustment should be applied to parameters of function templates when the parameter has a dependent type, however. For example:

        template<class T> struct A {
           typedef T arr[3];
        };

        template<class T> void f(const typename A<T>::arr) { } // #1

        template void f<int>(const A<int>::arr);

        template <class T> struct B {
           void g(T);
        };

        template <class T> void B<T>::g(const T) { } // #2

If the `const` in #1 is dropped, `f<int>` has a parameter type of `A*` rather than the `const A*` specified in the explicit instantiation. If the `const` in #2 is not dropped, we fail to match the definition of `B::g` to its declaration.

Rationale (November, 2010):

The CWG agreed that this behavior is intrinsic to the different ways cv-qualification applies to array types and non-array types.

Notes, January, 2012:

Additional discussion of this issue arose regarding the following example:

        template<class T> struct A {
          typedef double Point[2];
          virtual double calculate(const Point point) const = 0;
        };

        template<class T> struct B : public A<T> {
          virtual double calculate(const typename A<T>::Point point) const {
            return point[0];
          }
        };

        int main() {
          B<int> b;
          return 0;
        }

The question is whether the member function in `B<int>` has the same type as that in `A<int>`: is the parameter-type-list instantiated directly (i.e., using the adjusted types) or regenerated from the individual parameter types?

(See also issue 1322.)

#### 325. When are default arguments parsed?

Section: 8.3.6 [dcl.fct.default] Status: drafting Submitter: Nathan Sidwell Date: 27 Nov 2001

The standard is not precise enough about when the default arguments of member functions are parsed. This leads to confusion over whether certain constructs are legal or not, and the validity of certain compiler implementation algorithms.

8.3.6 [dcl.fct.default] paragraph 5 says "names in the expression are bound, and the semantic constraints are checked, at the point where the default argument expression appears"

However, further on at paragraph 9 in the same section there is an example, where the salient parts are

      int b;
      class X {
        int mem2 (int i = b); // OK use X::b
        static int b;
      };

which appears to contradict the former constraint. At the point the default argument expression appears in the definition of X, X::b has not been declared, so one would expect ::b to be bound. This of course appears to violate 3.3.7 [basic.scope.class] paragraph 1(2) "A name N used in a class S shall refer to the same declaration in its context and when reevaluated in the complete scope of S. No diagnostic is required."

Furthermore 3.3.7 [basic.scope.class] paragraph 1(1) gives the scope of names declared in class to "consist not only of the declarative region following the name's declarator, but also of .. default arguments ...". Thus implying that X::b is in scope in the default argument of X::mem2 previously.

That previous paragraph hints at an implementation technique of saving the token stream of a default argument expression and parsing it at the end of the class definition (much like the bodies of functions defined in the class). This is a technique employed by GCC and, from its behaviour, in the EDG front end. The standard leaves two things unspecified. Firstly, is a default argument expression permitted to call a static member function declared later in the class in such a way as to require evaluation of that function's default arguments? I.e. is the following well formed?

      class A {
        static int Foo (int i = Baz ());
        static int Baz (int i = Bar ());
        static int Bar (int i = 5);
     };

If that is well formed, at what point does the non-sensicalness of

      class B {
        static int Foo (int i = Baz ());
        static int Baz (int i = Foo());
      };

become detected? Is it when B is complete? Is it when B::Foo or B::Baz is called in such a way to require default argument expansion? Or is no diagnostic required?

The other problem is with collecting the tokens that form the default argument expression. Default arguments which contain template-ids with more than one parameter present a difficulty in determining when the default argument finishes. Consider,

      template <int A, typename B> struct T { static int i;};
      class C {
        int Foo (int i = T<1, int>::i);
      };

The default argument contains a non-parenthesized comma. Is it required that this comma is seen as part of the default argument expression and not the beginning of another of argument declaration? To accept this as part of the default argument would require name lookup of T (to determine that the '<' was part of a template argument list and not a less-than operator) before C is complete. Furthermore, the more pathological

      class D {
        int Foo (int i = T<1, int>::i);
        template <int A, typename B> struct T {static int i;};
      };

would be very hard to accept. Even though T is declared after Foo, T is in scope within Foo's default argument expression.

Suggested resolution:

Append the following text to 8.3.6 [dcl.fct.default] paragraph 8.

> The default argument expression of a member function declared in the class definition consists of the sequence of tokens up until the next non-parenthesized, non-bracketed comma or close parenthesis. Furthermore such default argument expressions shall not require evaluation of a default argument of a function declared later in the class.

This would make the above A, B, C and D ill formed and is in line with the existing compiler practice that I am aware of.

Notes from the October, 2005 meeting:

The CWG agreed that the first example (`A`) is currently well-formed and that it is not unreasonable to expect implementations to handle it by processing default arguments recursively.

Additional notes, May, 2009:

Presumably the following is ill-formed:

        int f(int = f());

However, it is not clear what in the Standard makes it so. Perhaps there needs to be a statement to the effect that a default argument only becomes usable after the complete declarator of which it is a part.

Notes from the August, 2011 meeting:

In addition to default arguments, commas in template argument lists also cause problems in initializers for nonstatic data members:

        struct S {
          int n = T<a,b>(c);  // ill-formed declarator for member b
                              // or template argument?
        };

(This is from #16 of the `IssuesFoundImplementingC0x.pdf` document on the Bloomington wiki.

Additional notes (August, 2011):

See also issues 1352 and 361.

Notes from the February, 2012 meeting:

It was decided to handle the question of parsing an initializer like `T<a,b>(c)` (a template-id or two declarators) in this issue and the remaining questions in issue 361. For this issue, a template-id will only be recognized if there is a preceding declaration of a template.

#### 361. Forward reference to default argument

Section: 8.3.6 [dcl.fct.default] Status: drafting Submitter: Steve Clamage Date: 17 June 2002

Is this program well-formed?

      struct S {
        static int f2(int = f1()); // OK?
        static int f1(int = 2);
      };
      int main()
      {
        return S::f2();
      }

A class member function can in general refer to class members that are declared lexically later. But what about referring to default arguments of member functions that haven't yet been declared?

It seems to me that if f2 can refer to f1, it can also refer to the default argument of f1, but at least one compiler disagrees.

Notes from the February, 2012 meeting:

Implementations seem to have come to agreement that this example is ill-formed.

#### 253. Why must empty or fully-initialized const objects be initialized?

Section: 8.5 [dcl.init] Status: drafting Submitter: Mike Miller Date: 11 Jul 2000

Paragraph 9 of 8.5 [dcl.init] says:

> If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for an object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.

What if a const POD object has no non-static data members? This wording requires an empty initializer for such cases:

        struct Z {
            // no data members
            operator int() const { return 0; }
        };

        void f() {
            const Z z1;         // ill-formed: no initializer
            const Z z2 = { };   // well-formed
        }

Similar comments apply to a non-POD const object, all of whose non-static data members and base class subobjects have default constructors. Why should the class of such an object be required to have a user-declared default constructor?

(See also issue 78.)

Additional note (February, 2011):

This issue should be brought up again in light of constexpr constructors and non-static data member initializers.

Notes from the August, 2011 meeting:

If the implicit default constructor initializes all subobjects, no initializer should be required.

#### 1507. Value initialization with trivial inaccessible default constructor

Section: 8.5 [dcl.init] Status: drafting Submitter: Johannes Schaub Date: 2012-06-01

According to 8.5 [dcl.init] paragraph 7, a trivial default constructor is not used in value initialization, so the following example would appear to be well-formed:

      struct A { private: A() = default; };
      int main() { A(); }

#### 1304. Omitted array bound with string initialization

Section: 8.5.2 [dcl.init.string] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-04-26

The example in 8.5.2 [dcl.init.string] paragraph 1 says,

>       char msg[] = "Syntax error on line %s\n";

> shows a character array whose members are initialized with a string-literal. Note that because `'\n'` is a single character and because a trailing `'\0'` is appended, `sizeof(msg)` is `25`.

However, there appears to be no normative specification of how the size of the array is to be calculated.

#### 233. References vs pointers in UDC overload resolution

Section: 8.5.3 [dcl.init.ref] Status: drafting Submitter: Matthias Meixner Date: 9 Jun 2000

There is an inconsistency in the handling of references vs pointers in user defined conversions and overloading. The reason for that is that the combination of 8.5.3 [dcl.init.ref] and 4.4 [conv.qual] circumvents the standard way of ranking conversion functions, which was probably not the intention of the designers of the standard.

Let's start with some examples, to show what it is about:

        struct Z { Z(){} };

        struct A {
           Z x;

           operator Z *() { return &x; }
           operator const Z *() { return &x; }
        };

        struct B {
           Z x;

           operator Z &() { return x; }
           operator const Z &() { return x; }
        };

        int main()
        {
           A a;
           Z *a1=a;
           const Z *a2=a; // not ambiguous

           B b;
           Z &b1=b;
           const Z &b2=b; // ambiguous
        }

So while both classes `A` and `B` are structurally equivalent, there is a difference in operator overloading. I want to start with the discussion of the pointer case (`const Z *a2=a;`): 13.3.3 [over.match.best] is used to select the best viable function. Rule 4 selects `A::operator const Z*()` as best viable function using 13.3.3.2 [over.ics.rank] since the implicit conversion sequence `const Z*` -> `const Z*` is a better conversion sequence than `Z*` -> `const Z*`.

So what is the difference to the reference case? Cv-qualification conversion is only applicable for pointers according to 4.4 [conv.qual]. According to 8.5.3 [dcl.init.ref] paragraphs 4-7 references are initialized by binding using the concept of reference-compatibility. The problem with this is, that in this context of binding, there is no conversion, and therefore there is also no comparing of conversion sequences. More exactly all conversions can be considered identity conversions according to 13.3.3.1.4 [over.ics.ref] paragraph 1, which compare equal and which has the same effect. So binding `const Z*` to `const Z*` is as good as binding `const Z*` to `Z*` in terms of overloading. Therefore `const Z &b2=b;` is ambiguous. [13.3.3.1.4 [over.ics.ref] paragraph 5 and 13.3.3.2 [over.ics.rank] paragraph 3 rule 3 (S1 and S2 are reference bindings ...) do not seem to apply to this case]

There are other ambiguities, that result in the special treatment of references: Example:

        struct A {int a;};
        struct B: public A { B() {}; int b;};

        struct X {
           B x;
           operator A &() { return x; }
           operator B &() { return x; }
        };

        main()
        {
           X x;
           A &g=x; // ambiguous
        }

Since both references of class `A` and `B` are reference compatible with references of class `A` and since from the point of ranking of implicit conversion sequences they are both identity conversions, the initialization is ambiguous.

So why should this be a defect?

- References behave fundamentally different from pointers in combination with user defined conversions, although there is no reason to have this different treatment.
- This difference only shows up in combination with user defined conversion sequences, for all other cases, there are special rules, e.g. 13.3.3.2 [over.ics.rank] paragraph 3 rule 3.

So overall I think this was not the intention of the authors of the standard.

So how could this be fixed? For comparing conversion sequences (and only for comparing) reference binding should be treated as if it was a normal assignment/initialization and cv-qualification would have to be defined for references. This would affect 8.5.3 [dcl.init.ref] paragraph 6, 4.4 [conv.qual] and probably 13.3.3.2 [over.ics.rank] paragraph 3.

Another fix could be to add a special case in 13.3.3 [over.match.best] paragraph 1.

#### 1414. Binding an rvalue reference to a reference-unrelated lvalue

Section: 8.5.3 [dcl.init.ref] Status: drafting Submitter: Mike Miller Date: 2011-11-09

Currently an attempt to bind an rvalue reference to a reference-unrelated lvalue succeeds, binding the reference to a temporary initialized from the lvalue by copy-initialization. This appears to be intentional, as the accompanying example contains the lines

        int i3 = 2;
        double&& rrd3 = i3;  // rrd3 refers to temporary with value 2.0

This violates the expectations of some who expect that rvalue references can be initialized only with rvalues. On the other hand, it is parallel with the handling of an lvalue reference-to-const (and is handled by the same wording). It also can add efficiency without requiring existing code to be rewritten: the implicitly-created temporary can be moved from, just as if the call had been rewritten to create a prvalue temporary from the lvalue explicitly.

On a related note, assuming the binding is permitted, the intent of the overload tiebreaker found in 13.3.3.2 [over.ics.rank] paragraph 3 is not clear:

- Standard conversion sequence `S1` is a better conversion sequence than standard conversion sequence `S2` if

- ...

- `S1` and `S2` are reference bindings (8.5.3 [dcl.init.ref]) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and `S1` binds an rvalue reference to an rvalue and `S2` binds an lvalue reference.

At question is what “to an rvalue” means here. If it is referring to the value category of the initializer itself, before conversions, then the supposed performance advantage of the binding under discussion does not occur because the competing rvalue and lvalue reference overloads will be ambiguous:

        void f(int&&);    // #1
        void f(const int&);
        void g(double d) {
            f(d);         // ambiguous: #1 does not bind to an rvalue
        }

On the other hand, if “to an rvalue” refers to the actual object to which the reference is bound, i.e., to the temporary in the case under discussion, the phrase would seem to be vacuous because an rvalue reference can never bind directly to an lvalue.

Notes from the February, 2012 meeting:

CWG agreed that the binding rules are correct, allowing creation of a temporary when binding an rvalue reference to a non-reference-related lvalue. The phrase “to an rvalue” in 13.3.3.2 [over.ics.rank] paragraph 3 is a leftover from before binding an rvalue reference to an lvalue was prohibited and should be removed. A change is also needed to handle the following case:

        void f(const char (&)[1]);         // #1
        template<typename T> void f(T&&);  // #2
        void g() {
          f("");                           //calls #2, should call #1
        }

Additional note (October, 2012):

Removing “to an rvalue,” as suggested, would have the effect of negating the preference for binding a function lvalue to an lvalue reference instead of an rvalue reference because the case would now fall under the preceding bullet of 13.3.3.2 [over.ics.rank] paragraph 3 bullet 1, sub-bullets 4 and 5:

> Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

> - Standard conversion sequence `S1` is a better conversion sequence than standard conversion sequence `S2` if

> - ...

> - `S1` and `S2` are reference bindings (8.5.3 [dcl.init.ref]) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and `S1` binds an rvalue reference to an rvalue and `S2` binds an lvalue reference... or, if not that,

> - `S1` and `S2` are reference bindings (8.5.3 [dcl.init.ref]) and `S1` binds an lvalue reference to a function lvalue and `S2` binds an rvalue reference to a function lvalue.

Presumably if the suggested resolution is adopted, the order of these two bullets should be inverted.

#### 1467. List-initialization of aggregate from same-type object

Section: 8.5.4 [dcl.init.list] Status: drafting Submitter: Jason Merrill Date: 2012-02-06

The current list-initialization rules do not provide for list-initialization of an aggregate from an object of the same type:

      struct X {
        X() = default;
        X(const X&) = default;
      #ifdef OK
        X(int) { }
      #endif
      };

      X x;
      X x2{x}; // error, {x} is not a valid aggregate initializer for X

Suggested resolution:

Change 8.5.4 [dcl.init.list] paragraph 3 as follows:

> List-initialization of an object or reference of type `T` is defined as follows:

> - If `T` is a class type and the initializer list has a single element of type cv `T` or a class type derived from `T`, the object is initialized from that element.

> - If Otherwise, if T is an aggregate...

Additional notes (September, 2012):

(See messages 22368, 22371 through 22373, 22388, and 22494.)

It appears that 13.3.3.1.5 [over.ics.list] will also need to be updated in parallel with this change. Alternatively, it may be better to change 8.5.1 [dcl.init.aggr] instead of 8.5.4 [dcl.init.list] and 13.3.3.1.5 [over.ics.list].

In a related note, given

      struct NonAggregate {
        NonAggregate() {}
      };

      struct WantsIt {
        WantsIt(NonAggregate);
      };

      void f(NonAggregate n);
      void f(WantsIt);

      int main() {
        NonAggregate n;
        // ambiguous!
        f({n});
      }

13.3.3.1.5 [over.ics.list] paragraph 3 says that the call to `f(NonAggregate)` is a user-defined conversion, the same as the call to `f(WantsIt)` and thus ambiguous. Also,

        NonAggregate n;
        // #1 (n -> NonAggregate = Identity conversion)
        NonAggregate m{n};
        // #2 ({n} -> NonAggregate = User-defined conversion}
        // (copy-ctor not considered according to 13.3.3.1 [over.best.ics] paragraph 4)
        NonAggregate m{{n}};

Finally, the suggested resolution simply says “initialized from,” without specifying whether that means direct initialization or copy initialization. It should be explicit about which is intended, e.g., if it reflects the kind of list-initialization being done.

#### 1490. List-initialization from a string literal

Section: 8.5.4 [dcl.init.list] Status: drafting Submitter: Daveed Vandevoorde Date: 2012-03-29

Initialization of an array of characters from a string literal is handled by the third bullet of 8.5 [dcl.init] paragraph 16, branching off to 8.5.2 [dcl.init.string]. However, list initialization is handled by the first bullet, branching off to 8.5.4 [dcl.init.list], and there is no corresponding special case in 8.5.4 [dcl.init.list] paragraph 3 for an array of characters initialized by a brace-enclosed string literal. That is, an initialization like

      char s[4]{"abc"};

is ill-formed, which could be surprising. Similarly,

      std::initializer_list<char>{"abc"};

is plausible but also not permitted.

Notes from the October, 2012 meeting:

CWG agreed that the first example should be permitted, but not the second.

#### 1494. Temporary initialization for reference binding in list-initialization

Section: 8.5.4 [dcl.init.list] Status: drafting Submitter: Steve Adamczyk Date: 2012-04-12

One of the bullets in 8.5.4 [dcl.init.list] paragraph 3 reads,

> Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary.

This does not say whether the initialization of the temporary is direct-list-initialization, copy-list-initialization, or the same kind of list-initialization as the top-level initialization.

#### 1518. Explicit default constructors and copy-list-initialization

Section: 8.5.4 [dcl.init.list] Status: drafting Submitter: Richard Smith Date: 2012-07-08

Consider the following example:

      struct A {
       explicit A() = default;
      };

      struct B : A {
       explicit B() = default;
      };

      struct C {
       explicit C();
      };

      struct D : A {
       C c;
       explicit D() = default;
      };

      template<typename T> void f() {
       T t = {};
      }
      template<typename T> void g() {
       void x(T t);
       x({});
      }

The question is whether `f<B>`, f`<C>`, `f<D>`, `g<B>`, `g<C>`, and `g<D>` are well-formed or ill-formed.

The crux here is whether 13.3.1.7 [over.match.list] is the governing law in each of these cases. If it is, the initialization is ill-formed, because copy-list-initialization has selected an explicit constructor. The standard seems clear that `f<A>` and `g<A>` are valid (because `A` is an aggregate, so 13.3.1.7 [over.match.list] is not reached nor applicable), `f<B>` is valid (because value-initialization does not call the default constructor, so 13.3.1.7 [over.match.list] is not reached), and that `g<B>`, `g<C>`, and `g<D>` are ill-formed (because 13.3.1.7 [over.match.list] is reached from 13.3.3.1.5 [over.ics.list] and selects an explicit constructor). The difference between `f<B>` and `g<B>` is troubling.

For `f<C>` and `f<D>`, it's not clear whether the default constructor call within value-initialization within list-initialization uses 13.3.1.7 [over.match.list] — but some form of overload resolution seems to be implied, since presumably we want to apply SFINAE to variadic constructor templates, diagnose classes which have multiple default constructors through the addition of default arguments, and the like.

It has been suggested that perhaps we are supposed to reach 13.3.1.7 [over.match.list] for an empty initializer list for a non-aggregate class with a default constructor only when we're coming from 13.3.3.1.5 [over.ics.list], and not when 8.5.4 [dcl.init.list] delegates to value-initialization. That would make all the `f`s valid, but `g<B>`, `g<C>`, and `g<D>` ill-formed.

12.3.1 [class.conv.ctor] paragraph 2 says explicit constructors are only used for direct-initialization or casts, which argues for at least `f<C>`, `f<D>`, `g<C>` and `g<D>` being ill-formed.

#### 1565. Copy elision and lifetime of `initializer_list` underlying array

Section: 8.5.4 [dcl.init.list] Status: drafting Submitter: Steve Adamczyk Date: 2012-10-10

If an `initializer_list` object is copied and the copy is elided, is the lifetime of the underlying array object extended? E.g.,

      void f() {
        std::initializer_list<int> L =
            std::initializer_list<int>{1, 2, 3}; // Lifetime of array extended?
      }

The current wording is not clear.

Notes from the October, 2012 meeting:

The consensus of CWG was that the behavior should be the same, regardless of whether the copy is elided or not.

#### 1496. Triviality with deleted and missing default constructors

Section: 9.1 [class.name] Status: drafting Submitter: Daniel Krügler Date: 2012-04-25

A default constructor that is defined as deleted is trivial, according to 12.1 [class.ctor] paragraph 5. This means that, according to 9 [class] paragraph 6, such a class can be trivial. If, however, the class has no default constructor because it has a user-declared constructor, the class is not trivial. Since both cases prevent default construction of the class, it is not clear why there is a difference in triviality between the cases.

Notes from the October, 2012 meeting:

It was observed that this issue was related to issue 1344, as the current specification allows adding a default constructor by adding default arguments to the definition of a constructor. The resolution of that issue should also resolve this one.

#### 1341. Bit-field initializers

Section: 9.2 [class.mem] Status: drafting Submitter: James Widman Date: 2011-08-10

The grammar for member-declarator (9.2 [class.mem]) does not, but should, allow for a brace-or-equal-initializer on a bit-field declarator.

#### 1283. Static data members of classes with typedef name for linkage purposes

Section: 9.4.2 [class.static.data] Status: drafting Submitter: Mike Miller Date: 2011-03-29

According to 9.4.2 [class.static.data] paragraph 4,

> Unnamed classes and classes contained directly or indirectly within unnamed classes shall not contain static data members.

There is no such restriction on member functions, and there is no rationale for this difference, given that both static data members and member functions can be defined outside a unnamed class with a typedef name for linkage purposes. (Issue 406 acknowledged the lack of rationale by removing the specious note in 9.4.2 [class.static.data] that attempted to explain the restriction but left the normative prohibition in place.)

It would be more consistent to remove the restriction for classes with a typedef name for linkage purposes.

Additional note (August, 2012):

It was observed that, since no definition of a `const` static data member is required if it is not odr-used, there is no reason to prohibit such members in an unnamed class even without a typedef name for linkage purposes.

#### 1404. Object reallocation in unions

Section: 9.5 [class.union] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-10-19

According to 9.5 [class.union] paragraph 4,

> [Note: In general, one must use explicit destructor calls and placement new operators to change the active member of a union. —end note] [Example: Consider an object `u` of a union type `U` having non-static data members `m` of type `M` and `n` of type `N`. If `M` has a non-trivial destructor and `N` has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of `u` can be safely switched from `m` to `n` using the destructor and placement new operator as follows:

>       u.m.~M();
>       new (&u.n)  N;

> —end example]

This pattern is only “safe” if the original object that is being destroyed does not involve any const-qualified or reference types, i.e., satisfies the requirements of 3.8 [basic.life] paragraph 7, bullet 3:

- the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type

Although paragraph 4 of 9.5 [class.union] is a note and an example, it should at least refer to the lifetime issues described in 3.8 [basic.life].

#### 1460. What is an empty union?

Section: 9.5 [class.union] Status: drafting Submitter: Jason Merrill Date: 2012-02-08

When a similar question was raised in issue 413, the resolution was to remove the use of the term. The resolution of issue 1359 has now reintroduced the concept of an “empty” union, so there is once again the need to define it.

#### 952. Insufficient description of “naming class”

Section: 11.2 [class.access.base] Status: drafting Submitter: James Widman Date: 7 August, 2009

The access rules in 11.2 [class.access.base] do not appear to handle references in nested classes and outside of nonstatic member functions correctly. For example,

        struct A {
            typedef int I;    // public
        };
        struct B: private A { };
        struct C: B {
            void f() {
                I i1;         // error: access violation
            }
            I i2;             // OK
            struct D {
                I i3;         // OK
                void g() {
                    I i4;     // OK
                }
            };
        };

The reason for this discrepancy is that the naming class in the reference to `I` is different in these cases. According to 11.2 [class.access.base] paragraph 5,

> The access to a member is affected by the class in which the member is named. This naming class is the class in which the member name was looked up and found.

In the case of `i1`, the reference to `I` is subject to the transformation described in 9.3.1 [class.mfct.non-static] paragraph 3:

> Similarly during name lookup, when an unqualified-id (5.1 [expr.prim]) used in the definition of a member function for class `X` resolves to a `static` member, an enumerator or a nested type of class `X` or of a base class of `X`, the unqualified-id is transformed into a qualified-id (5.1 [expr.prim]) in which the nested-name-specifier names the class of the member function.

As a result, the reference to `I` in the declaration of `i1` is transformed to `C::I`, so that the naming class is `C`, and `I` is inacessible in `C`. In the remaining cases, however, the transformation does not apply. Thus, the naming class of `I` in these references is `A`, and `I` is publicly accessible in `A`.

Presumably either the definition of “naming class” must be changed or the transformation of unqualified-ids must be broadened to include all uses within the scope of a class and not just within nonstatic member functions (and following the declarator-id in the definition of a static member, per 9.4 [class.static] paragraph 4).

#### 472. Casting across protected inheritance

Section: 11.4 [class.protected] Status: drafting Submitter: Mike Miller Date: 16 Jun 2004

Does the restriction in 11.4 [class.protected] apply to upcasts across protected inheritance, too? For instance,

        struct B {
            int i;
        };
        struct I: protected B { };
        struct D: I {
            void f(I* ip) {
                B* bp = ip;    // well-formed?
                bp->i = 5;     // aka "ip->i = 5;"
            }
        };

I think the rationale for the 11.4 [class.protected] restriction applies equally well here — you don't know whether `ip` points to a `D` object or not, so `D::f` can't be trusted to treat the protected `B` subobject consistently with the policies of its actual complete object type.

The current treatment of “accessible base class” in 11.2 [class.access.base] paragraph 4 clearly makes the conversion from `I*` to `B*` well-formed. I think that's wrong and needs to be fixed. The rationale for the accessibility of a base class is whether “an invented public member” of the base would be accessible at the point of reference, although we obscured that a bit in the reformulation; it seems to me that the invented member ought to be considered a non-static member for this purpose and thus subject to 11.4 [class.protected].

(See also issues 385 and 471.).

Notes from October 2004 meeting:

The CWG tentatively agreed that casting across protective inheritance should be subject to the additional restriction in 11.4 [class.protected].

Proposed resolution (April, 2011)

Change 11.2 [class.access.base] paragraph 4 as follows:

> A base class `B` of `N` is accessible at R, if

> - an invented public member of `B` would be a public member of `N`, or

> - R occurs in a member or friend of class `N`, and an invented public member of `B` would be a private or protected member of `N`, or

> - R occurs in a member or friend of a class `P` derived from `N`, and an invented public member of `B` would be a private or (but not a protected [Footnote: A protected invented member is disallowed here for the same reason the additional check of 11.4 [class.protected] is applied to member access: it would allow casting a pointer to a derived class to a protected base class that might be a subobject of an object of a class that is different from the class context in which the reference occurs. —end footnote]) member of `P`, or

> - there exists a class `S` such that `B` is a base class of `S` accessible at R and `S` is a base class of `N` accessible at R.

> [Example:

>         class B {
>         public:
>           int m;
>         };

>         class S: private B {
>           friend class N;
>         };
>         class N: private S {
>           void f() {
>             B* p = this;    // OK because class S satisfies the fourth condition
>                             // above: B is a base class of N accessible in f() because
>                             // B is an accessible base class of S and S is an accessible
>                             // base class of N.
>           }
>         };

>         class N2: protected B { };

>         class P2: public N2 {
>           void f2(N2* n2p) {
>             B* bp = n2p;    // error: invented member would be protected and naming
>                             // class N2 not the same as or derived from the referencing
>                             // class P2
>             n2p->m = 0;     // error (cf 11.4 [class.protected]) for the same reason
>           }
>         };

> —end example]

#### 1353. Array and variant members and deleted special member functions

Section: 12.1 [class.ctor] Status: drafting Submitter: Sean Hunt Date: 2011-08-16

The specification of when a defaulted special member function is to be defined as deleted sometimes overlooks variant and array members.

#### 1360. `constexpr` defaulted default constructors

Section: 12.1 [class.ctor] Status: drafting Submitter: Richard Smith Date: 2011-08-16

According to 12.1 [class.ctor] paragraph 6, a defaulted default constructor is `constexpr` if the corresponding user-written constructor would satisfy the `constexpr` requirements. However, the requirements apply to the definition of a constructor, and a defaulted constructor is defined only if it is odr-used, leaving it indeterminate at declaration time whether the defaulted constructor is `constexpr` or not.

(See also issue 1358.)

#### 399. Destructor lookup redux

Section: 12.4 [class.dtor] Status: drafting Submitter: John Spicer Date: 17 Jan 2003

Mark Mitchell raised a number of issues related to the resolution of issue 244 and of destructor lookup in general.

Issue 244 says:

> ... in a qualified-id of the form:
> ::opt nested-name-specifieropt class-name :: ~ class-name
> the second class-name is looked up in the same scope as the first.

But if the reference is "`p->X::~X()`", the first class-name is looked up in two places (normal lookup and a lookup in the class of p). Does the new wording mean:

1. You look up the second class-name in the scope that you found the first one.
2. You look up the second class-name using the same kind of lookup that found the first one (normal vs. class).
3. If you did a dual lookup for the first you do a dual lookup for the second.

This is a test case that illustrates the issue:

      struct A {
        typedef A C;
      };

      typedef A B;

      void f(B* bp) {
        bp->B::~B();  // okay B found by normal lookup
        bp->C::~C();  // okay C found by class lookup
        bp->B::~C();  // B found by normal lookup C by class -- okay?
        bp->C::~B();  // C found by class lookup B by normal -- okay?
      }

A second issue concerns destructor references when the class involved is a template class.

      namespace N {
        template <typename T> struct S {
          ~S();
        };
      }

      void f(N::S<int>* s) {
        s->N::S<int>::~S();
      }

The issue here is that the grammar uses "~class-name" for destructor names, but in this case S is a template name when looked up in N.

Finally, what about cases like:

      template <typename T> void f () {
        typename T::B x;
        x.template A<T>::template B<T>::~B();
      }

When parsing the template definition, what checks can be done on "~B"?

Sandor Mathe adds :

The standard correction for issue 244 (now in DR status) is still incomplete.

Paragraph 5 of 3.4.3 [basic.lookup.qual] is not applicable for p->T::~T since there is no nested-name-specifier. Section 3.4.5 [basic.lookup.classref] describes the lookup of p->~T but p->T::~T is still not described. There are examples (which are non-normative) that illustrate this sort of lookup but they still leave questions unanswered. The examples imply that the name after ~ should be looked up in the same scope as the name before the :: but it is not stated. The problem is that the name to the left of the :: can be found in two different scopes. Consider the following:

      struct S {
        struct C { ~C() { } };
      };

      typedef S::C D;

      int main() {
        D* p;
        p->C::~D();  // valid?
      }

Should the destructor call be valid? If there were a nested name specifier, then D should be looked for in the same scope as C. But here, C is looked for in 2 different ways. First, it is searched for in the type of the left hand side of -> and it is also looked for in the lexical context. It is found in one or if both, they must match. So, C is found in the scope of what p points at. Do you only look for D there? If so, this is invalid. If not, you would then look for D in the context of the expression and find it. They refer to the same underlying destructor so this is valid. The intended resolution of the original defect report of the standard was that the name before the :: did not imply a scope and you did not look for D inside of C. However, it was not made clear whether this was to be resolved by using the same lookup mechanism or by introducing a new form of lookup which is to look in the left hand side if that is where C was found, or in the context of the expression if that is where C was found. Of course, this begs the question of what should happen when it is found in both? Consider the modification to the above case when C is also found in the context of the expression. If you only look where you found C, is this now valid because it is in 1 of the two scopes or is it invalid because C was in both and D is only in 1?

      struct S {
        struct C { ~C() { } };
      };

      typedef S::C D;
      typedef S::C C;

      int main() {
        D* p;
        p->C::~D();  // valid?
      }

I agree that the intention of the committee is that the original test case in this defect is broken. The standard committee clearly thinks that the last name before the last :: does not induce a new scope which is our current interpretation. However, how this is supposed to work is not defined. This needs clarification of the standard.

Martin Sebor adds this example (September 2003), along with errors produced by the EDG front end:

    namespace N {
        struct A { typedef A NA; };
        template <class T> struct B { typedef B NB; typedef T BT; };
        template <template <class> class T> struct C { typedef C NC; typedef T<A> CA; };
    }

    void foo (N::A *p)
    {
        p->~NA ();
        p->NA::~NA ();
    }

    template <class T>
    void foo (N::B<T> *p)
    {
        p->~NB ();
        p->NB::~NB ();
    }

    template <class T>
    void foo (typename N::B<T>::BT *p)
    {
        p->~BT ();
        p->BT::~BT ();
    }

    template <template <class> class T>
    void foo (N::C<T> *p)
    {
        p->~NC ();
        p->NC::~NC ();
    }

    template <template <class> class T>
    void foo (typename N::C<T>::CA *p)
    {
        p->~CA ();
        p->CA::~CA ();
    }

    Edison Design Group C/C++ Front End, version 3.3 (Sep  3 2003 11:54:55)
    Copyright 1988-2003 Edison Design Group, Inc.

    "t.cpp", line 16: error: invalid destructor name for type "N::B<T>"
          p->~NB ();
              ^

    "t.cpp", line 17: error: qualifier of destructor name "N::B<T>::NB" does not
              match type "N::B<T>"
          p->NB::~NB ();
                  ^

    "t.cpp", line 30: error: invalid destructor name for type "N::C<T>"
          p->~NC ();
              ^

    "t.cpp", line 31: error: qualifier of destructor name "N::C<T>::NC" does not
              match type "N::C<T>"
          p->NC::~NC ();
                  ^

    4 errors detected in the compilation of "t.cpp".

John Spicer: The issue here is that we're unhappy with the destructor names when doing semantic analysis of the template definitions (not during an instantiation).

My personal feeling is that this is reasonable. After all, why would you call p->~NB for a class that you just named as N::B<T> and you could just say p->~B?

Additional note (September, 2004)

The resolution for issue 244 removed the discussion of `p->N::~S`, where `N` is a namespace-name. However, the resolution did not make this construct ill-formed; it simply left the semantics undefined. The meaning should either be defined or the construct made ill-formed.

See also issues 305 and 466.

#### 255. Placement deallocation functions and lookup ambiguity

Section: 12.5 [class.free] Status: drafting Submitter: Mike Miller Date: 26 Oct 2000

Paragraph 4 of 12.5 [class.free] speaks of looking up a deallocation function. While it is an error if a placement deallocation function alone is found by this lookup, there seems to be an assumption that a placement deallocation function and a usual deallocation function can both be declared in a given class scope without creating an ambiguity. The normal mechanism by which ambiguity is avoided when functions of the same name are declared in the same scope is overload resolution; however, there is no mention of overload resolution in the description of the lookup. In fact, there appears to be nothing in the current wording that handles this case. That is, the following example appears to be ill-formed, according to the current wording:

        struct S {
            void operator delete(void*);
            void operator delete(void*, int);
        };
        void f(S* p) {
            delete p;    // ill-formed: ambiguous operator delete
        }

Suggested resolution (Mike Miller, March 2002):

I think you might get the right effect by replacing the last sentence of 12.5 [class.free] paragraph 4 with something like:

> After removing all placement deallocation functions, the result of the lookup shall contain an unambiguous and accessible deallocation function.

Additional notes (October, 2012):

This issue should be reconsidered in list of paper N3396, as it would add additional overloads for allocation and deallocation functions.

The term “usual deallocation function” is defined in 3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 2; perhaps it could be used to good effect in 5.3.5 [expr.delete] paragraph 7. The specifications in 12.5 [class.free] paragraphs 4 and 5 should probably also be moved into 5.3.5 [expr.delete].

#### 1562. Non-static data member initializers and union ctor-initializer

Section: 12.6.2 [class.base.init] Status: drafting Submitter: Richard Smith Date: 2012-10-01

The following example is ill-formed:

      union U {
        int a = 0;
        float f;
        U() {}               // ok, a initialized to 0
        U(float f) : f(f) {} // error, constructor initializes both a and f
      };

because of 12.6.2 [class.base.init] paragraph 8:

> An attempt to initialize more than one non-static data member of a union renders the program ill-formed.

In non-union classes, a mem-initializer takes precedence over a non-static data member initializer, per paragraph 9:

> If a given non-static data member has both a brace-or-equal-initializer and a mem-initializer, the initialization specified by the mem-initializer is performed, and the non-static data member's brace-or-equal-initializer is ignored.

It would be reasonable to treat union mem-initializers in an analogous fashion.

#### 1517. Unclear/missing description of behavior during construction/destruction

Section: 12.7 [class.cdtor] Status: drafting Submitter: Daniel Krügler Date: 2012-07-07

The current wording of 12.7 [class.cdtor] paragraph 4 does not describe the behavior of calling a virtual function in a mem-initializer for a base class, only for a non-static data member. Also, the changes for issue 1202 should have been, but were not, applied to the description of the behavior of `typeid` and `dynamic_cast` in paragraphs 5 and 6.

In addition, the resolution of issue 597 allowing the out-of-lifetime conversion of pointers/lvalues to non-virtual base classes, should have been, but were not, applied to paragraph 3.

#### 1092. Cycles in overload resolution during instantiation

Section: 12.8 [class.copy] Status: drafting Submitter: Jason Merrill Date: 2010-07-15

Moving to always doing overload resolution for determining exception specifications and implicit deletion creates some unfortunate cycles:

        template<typename T> struct A {
           T t;
        };

        template <typename T> struct B {
           typename T::U u;
        };

        template <typename T> struct C {
           C(const T&);
        };

        template <typename T> struct D {
           C<B<T> > v;
        };

        struct E {
           typedef A<D<E> > U;
        };

        extern A<D<E> > a;
        A<D<E> > a2(a);

If declaring the copy constructor for `A<D<E>>` is part of instantiating the class, then we need to do overload resolution on `D<E>`, and thus `C<B<E>>`. We consider `C(const B<E>&)`, and therefore look to see if there's a conversion from `C<B<E>>` to `B<E>`, which instantiates `B<E>`, which fails because it has a field of type `A<D<E>>` which is already being instantiated.

Even if we wait until `A<D<E>>` is considered complete before finalizing the copy constructor declaration, declaring the copy constructor for `B<E>` will want to look at the copy constructor for `A<D<E>>`, so we still have the cycle.

I think that to avoid this cycle we need to short-circuit consideration of `C(const T&)` somehow. But I don't see how we can do that without breaking

        struct F {
           F(F&);
        };

        struct G;
        struct G2 {
           G2(const G&);
        };

        struct G {
           G(G&&);
           G(const G2&);
        };

        struct H: F, G { };

        extern H h;
        H h2(h);

Here, since `G`'s move constructor suppresses the implicit copy constructor, the defaulted `H` copy constructor calls `G(const G2&)` instead. If the move constructor did not suppress the implicit copy constructor, I believe the implicit copy constructor would always be viable, and therefore a better match than a constructor taking a reference to another type.

So perhaps the answer is to reconsider that suppression and then disqualify any constructor taking (a reference to) a type other than the constructor's class from consideration when looking up a subobject constructor in an implicitly defined constructor. (Or assignment operator, presumably.)

Another possibility would be that when we're looking for a conversion from `C<B<E>>` to `B<E>` we could somehow avoid considering, or even declaring, the `B<E>` copy constructor. But that seems a bit dodgy.

Additional note (October, 2010):

An explicitly declared move constructor/op= should not suppress the implicitly declared copy constructor/op=; it should cause it to be deleted instead. This should prevent a member function taking a (reference to) an un-reference-related type from being chosen by overload resolution in a defaulted member function.

And we should clarify that member functions taking un-reference-related types are not even considered during overload resolution in a defaulted member function, to avoid requiring their parameter types to be complete.

#### 1344. Adding new special member functions to a class via default arguments

Section: 12.8 [class.copy] Status: drafting Submitter: Sean Hunt Date: 2011-08-16

If default arguments added in the out-of-class definition of a constructor make it a special member function, this can affect the overload resolution and thus the implicit exception specification and the triviality of an implicitly-declared special member function in a derived class.

See also issue 1496, which should also be addressed by the resolution of this issue.

#### 1491. Move construction and rvalue reference members

Section: 12.8 [class.copy] Status: drafting Submitter: Richard Smith Date: 2012-03-30

According to 12.8 [class.copy] paragraph 11, the last bullet, a defaulted move constructor for a class is defined as deleted if

> a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.

This means that an example like

      struct S { S(); int &&r; } s{S()};

is ill-formed. This is probably not intended.

(Note that the February, 2012 proposed resolution for issue 1402 also makes this example ill-formed, because the move constructor is not declared and the copy constructor is defined as deleted because of the rvalue-reference member.)

#### 1493. Criteria for move-construction

Section: 12.8 [class.copy] Status: drafting Submitter: John Spicer Date: 2012-04-02

The decision in 12.8 [class.copy] paragraph 32 on whether or not a copy must be replaced by a move is phrased largely in terms of when copy elision can be performed, as described in the preceding paragraph. In particular, the fourth bullet of paragraph 31 applies

> when the exception-declaration of an exception handler (Clause 15 [except]) declares an object of the same type (except for cv-qualification) as the exception object (15.1 [except.throw]), the copy/move operation can be omitted by treating the exception-declaration as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the exception-declaration.

The determination of “when the meaning of the program will be unchanged” is, in the general case, not practical. Copy elision is optional, meaning that the compiler can simply choose not to perform it if the determination is too difficult. Choosing whether to do a copy or a move, however, is mandatory, even if the copy is elided, and such a broad criterion is not appropriate. Probably the best way to address this problem would be to eliminate exception-declarations as a possible target for move-construction.

#### 1499. Missing case for deleted move assignment operator

Section: 12.8 [class.copy] Status: drafting Submitter: John Spicer Date: 2012-04-27

Bullet 4 of 12.8 [class.copy] paragraph 23 says that a defaulted copy/move assignment operator is defined as deleted if the class has

> a non-static data member of class type `M` (or array thereof) that cannot be copied/moved because overload resolution (13.3 [over.match]), as applied to `M`'s corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator

The intent of this is that if overload resolution fails to find a corresponding copy/move assignment operator that can validly be called to copy/move a member, the class's assignment operator will be defined as deleted. However, this wording does not cover an example like the following:

      struct A {
        A();
      };

      struct B {
        B();
        const A a;
      };

      typedef B& (B::*pmf)(B&&);

      pmf p =&B::operator=;

Here, the problem is simply that overload resolution failed to find a callable function, which is not one of the cases listed in the current wording. A similar problem exists for base classes in the fifth bullet.

#### 1548. Copy/move construction and conversion functions

Section: 12.8 [class.copy] Status: drafting Submitter: Nikolay Ivchenkov Date: 2012-09-0w

The current wording of 12.8 [class.copy] paragraph 31 refers only to constructors and destructors:

> When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.

However, in some cases (e.g., `auto_ptr`) a conversion function is also involved in the copying, and it could presumably also have visible side effects that would be eliminated by copy elision. (Some additional contexts that may also require changes in this regard are mentioned in the resolution of issue 535.)

Additional note (September, 2012):

The default arguments of an elided constructor can also have side effects and should be mentioned, as well; however, the elision should not change the odr-use status of functions and variables appearing in those default arguments.

#### 1487. When are inheriting constructors declared?

Section: 12.9 [class.inhctor] Status: drafting Submitter: Richard Smith Date: 2012-03-27

According to 12.9 [class.inhctor] paragraph 3,

> For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the class where the using-declaration appears.

It is not clear whether that determination is intended to include constructors declared after the point of the using-declaration or not.

#### 1252. Overloading member function templates based on dependent return type

Section: 13.1 [over.load] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-06

The Standard does not allow overloading of member functions that differ only in their return type (cf `enable_if`).

#### 1278. Incorrect treatment of contrived object

Section: 13.3.1.1.1 [over.call.func] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-27

Footnote 127 of 13.3.1.1.1 [over.call.func] paragraph 3 reads,

> An implied object argument must be contrived to correspond to the implicit object parameter attributed to member functions during overload resolution. It is not used in the call to the selected function. Since the member functions all have the same implicit object parameter, the contrived object will not be the cause to select or reject a function.

It is not true that “the member functions all have the same implicit object parameter.” This statement does not take into account member functions brought into the class by using-declarations or cv-qualifiers and ref-qualifiers on the non-static member functions:

        struct B
        {
          char f();         // B &
        };

        struct D : B
        {
          using B::f;
          long f();         // D &

          char g() const;   // D const &
          long g();         // D &

          char h() &;       // D &
          long h() &&;      // D &&
        };

        int main()
        {
          // D::f() has better match than B::f()
          decltype(D().f()) *p1 = (long *)0;

          // D::g() has better match than D::g() const
          decltype(D().g()) *p2 = (long *)0;

          // D::h() & is not viable function
          // D::h() && is viable function
          decltype(D().h()) *p3 = (long *)0;
        }

The value category of a contrived object expression is not specified by the rules and, probably, cannot be properly specified in presence of ref-qualifiers, so the statement “the contrived object will not be the cause to select or reject a function” should be normative rather than informative:

        struct X
        {
          static void f(double) {}
          void f(int) & {}
          void f(int) && {}
        };

        int main()
        {
          X::f(0); // ???
        }

#### 455. Partial ordering and non-deduced arguments

Section: 13.3.3 [over.match.best] Status: drafting Submitter: Rani Sharoni Date: 19 Jan 2004

It's not clear how overloading and partial ordering handle non-deduced pairs of corresponding arguments. For example:

    template<typename T>
    struct A { typedef char* type; };

    template<typename T> char* f1(T, typename A<T>::type);  // #1
    template<typename T> long* f1(T*, typename A<T>::type*); // #2

    long* p1 = f1(p1, 0); // #3

I thought that #3 is ambiguous but different compilers disagree on that. Comeau C/C++ 4.3.3 (EDG 3.0.3) accepted the code, GCC 3.2 and BCC 5.5 selected #1 while VC7.1+ yields ambiguity.

I intuitively thought that the second pair should prevent overloading from triggering partial ordering since both arguments are non-deduced and has different types - (char*, char**). Just like in the following:

    template<typename T> char* f2(T, char*);   // #3
    template<typename T> long* f2(T*, char**); // #4

    long* p2 = f2(p2, 0); // #5

In this case all the compilers I checked found #5 to be ambiguous. The standard and DR 214 is not clear about how partial ordering handle such cases.

I think that overloading should not trigger partial ordering (in step 13.3.3 [over.match.best]/1/5) if some candidates have non-deduced pairs with different (specialized) types. In this stage the arguments are already adjusted so no need to mention it (i.e. array to pointer). In case that one of the arguments is non-deuced then partial ordering should only consider the type from the specialization:

    template<typename T> struct B { typedef T type; };

    template<typename T> char* f3(T, T);                   // #7
    template<typename T> long* f3(T, typename B<T>::type); // #8

    char* p3 = f3(p3, p3); // #9

According to my reasoning #9 should yield ambiguity since second pair is (T, long*). The second type (i.e. long*) was taken from the specialization candidate of #8. EDG and GCC accepted the code. VC and BCC found an ambiguity.

John Spicer: There may (or may not) be an issue concerning whether nondeduced contexts are handled properly in the partial ordering rules. In general, I think nondeduced contexts work, but we should walk through some examples to make sure we think they work properly.

Rani's description of the problem suggests that he believes that partial ordering is done on the specialized types. This is not correct. Partial ordering is done on the templates themselves, independent of type information from the specialization.

Notes from October 2004 meeting:

John Spicer will investigate further to see if any action is required.

(See also issue 885.)

#### 1307. Overload resolution based on size of array `initializer-list`

Section: 13.3.3.1.5 [over.ics.list] Status: drafting Submitter: Johannes Schaub Date: 2011-04-30

In an example like

      void f(int const(&)[2]);
      void f(int const(&)[3]);

      int main() {
       f({1, 2, 3});
      }

the current overload resolution rules make no provision for different array sizes and thus treats the call as ambiguous, even though it seems obvious that the second `f` should be chosen in this case.

Rationale (August, 2011):

The implications of array temporaries for the language should be considered by the Evolution Working Group in a comprehensive fashion rather than on a case-by-case basis. See also issues 1300, 1326, and 1525.

Notes from the October, 2012 meeting:

CWG determined that this issue is unrelated to array temporaries and that a tiebreaker should be added for this case in overload resolution.

#### 1536. Overload resolution with temporary from initializer list

Section: 13.3.3.1.5 [over.ics.list] Status: drafting Submitter: Mike Miller Date: 2012-08-14

In determining the implicit conversion sequence for an initializer list argument passed to a reference parameter, the intent is that a temporary of the appropriate type will be created and bound to the reference, as reflected in 13.3.3.1.5 [over.ics.list] paragraph 5:

> Otherwise, if the parameter is a reference, see 13.3.3.1.4 [over.ics.ref]. [Note: The rules in this section will apply for initializing the underlying temporary for the reference. —end note]

However, 13.3.3.1.4 [over.ics.ref] deals only with expression arguments, not initializer lists:

> When a parameter of reference type binds directly (8.5.3 [dcl.init.ref]) to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion (13.3.3.1 [over.best.ics])... If the parameter binds directly to the result of applying a conversion function to the argument expression, the implicit conversion sequence is a user-defined conversion sequence (13.3.3.1.2 [over.ics.user]), with the second standard conversion sequence either an identity conversion or, if the conversion function returns an entity of a type that is a derived class of the parameter type, a derived-to-base Conversion.

> When a parameter of reference type is not bound directly to an argument expression, the conversion sequence is the one required to convert the argument expression to the underlying type of the reference according to 13.3.3.1 [over.best.ics]. Conceptually, this conversion sequence corresponds to copy-initializing a temporary of the underlying type with the argument expression. Any difference in top-level cv-qualification is subsumed by the initialization itself and does not constitute a conversion.

(Note in particular that the reference binding refers to 8.5.3 [dcl.init.ref], which also does not handle initializer lists, and not to 8.5.4 [dcl.init.list].)

Either 13.3.3.1.4 [over.ics.ref] needs to be revised to handle binding references to initializer list arguments or 13.3.3.1.5 [over.ics.list] paragraph 5 needs to be clearer on how the expression specification is intended to be applied to initializer lists.

#### 1563. List-initialization and overloaded function disambiguation

Section: 13.4 [over.over] Status: drafting Submitter: Daniel Krügler Date: 2012-10-08

Presumably, 13.4 [over.over] paragraph 1,

> A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note] The target can be

> - an object or reference being initialized (8.5 [dcl.init], 8.5.3 [dcl.init.ref]),

> - ...

should apply to an example like

      double bar(double) { return 0.0; }
      float bar(float) { return 0.0f; }

      using fun = double(double);
      fun &foo{bar};

However, there is implementation variance in whether the use of `bar` is accepted or not, and the omission of a cross-reference to 8.5.4 [dcl.init.list] might be read as indicating that list-initialization is not included.

#### 260. User-defined conversions and built-in `operator=`

Section: 13.6 [over.built] Status: drafting Submitter: Scott Douglas Date: 4 Nov 2000

According to the Standard (although not implemented this way in most implementations), the following code exhibits non-intuitive behavior:

      struct T {
        operator short() const;
        operator int() const;
      };

      short s;

      void f(const T& t) {
        s = t;  // surprisingly calls T::operator int() const
      }

The reason for this choice is 13.6 [over.built] paragraph 18:

> For every triple (L, VQ, R), where L is an arithmetic type, VQ is either `volatile` or empty, and R is a promoted arithmetic type, there exist candidate operator functions of the form

> VQ L`& operator=(`VQ L`&,` R`);`

Because R is a "promoted arithmetic type," the second argument to the built-in assignment operator is `int`, causing the unexpected choice of conversion function.

Suggested resolution: Provide built-in assignment operators for the unpromoted arithmetic types.

Related to the preceding, but not resolved by the suggested resolution, is the following problem. Given:

        struct T {
    	 operator int() const;
    	 operator double() const;
        };

I believe the standard requires the following assignment to be ambiguous (even though I expect that would surprise the user):

        double x;
        void f(const T& t) { x = t; }

The problem is that both of these built-in `operator=()`s exist (13.6 [over.built] paragraph 18):

        double& operator=(double&, int);
        double& operator=(double&, double);

Both are an exact match on the first argument and a user conversion on the second. There is no rule that says one is a better match than the other.

The compilers that I have tried (even in their strictest setting) do not give a peep. I think they are not following the standard. They pick `double& operator=(double&, double)` and use `T::operator double() const`.

I hesitate to suggest changes to overload resolution, but a possible resolution might be to introduce a rule that, for built-in `operator=` only, also considers the conversion sequence from the second to the first type. This would also resolve the earlier question.

It would still leave `x += t` etc. ambiguous -- which might be the desired behavior and is the current behavior of some compilers.

Notes from the 04/01 meeting:

The difference between initialization and assignment is disturbing. On the other hand, promotion is ubiquitous in the language, and this is the beginning of a very slippery slope (as the second report above demonstrates).

Additional note (August, 2010):

See issue 507 for a similar example involving comparison operators.

#### 205. Templates and static data members

Section: 14 [temp] Status: drafting Submitter: Mike Miller Date: 11 Feb 2000

Static data members of template classes and of nested classes of template classes are not themselves templates but receive much the same treatment as template. For instance, 14 [temp] paragraph 1 says that templates are only "classes or functions" but implies that "a static data member of a class template or of a class nested within a class template" is defined using the template-declaration syntax.

There are many places in the clause, however, where static data members of one sort or another are overlooked. For instance, 14 [temp] paragraph 6 allows static data members of class templates to be declared with the `export` keyword. I would expect that static data members of (non-template) classes nested within class templates could also be exported, but they are not mentioned here.

Paragraph 8, however, overlooks static data members altogether and deals only with "templates" in defining the effect of the `export` keyword; there is no description of the semantics of defining a static data member of a template to be exported.

These are just two instances of a systematic problem. The entire clause needs to be examined to determine which statements about "templates" apply to static data members, and which statements about "static data members of class templates" also apply to static data members of non-template classes nested within class templates.

(The question also applies to member functions of template classes; see issue 217, where the phrase "non-template function" in 8.3.6 [dcl.fct.default] paragraph 4 is apparently intended not to include non-template member functions of template classes. See also issue 108, which would benefit from understanding nested classes of class templates as templates. Also, see issue 249, in which the usage of the phrase "member function template" is questioned.)

Notes from the 4/02 meeting:

Daveed Vandevoorde will propose appropriate terminology.

#### 1444. Type adjustments of non-type template parameters

Section: 14.1 [temp.param] Status: drafting Submitter: Johannes Schaub Date: 2012-01-15

The type adjustment of template non-type parameters described in 14.1 [temp.param] paragraph 8 appears to be underspecified. For example, implementations vary in their treatment of

      template<typename T, T[T::size]> struct A {};
      int dummy;
      A<int, &dummy> a;

and

      template<typename T, T[1]> struct A;
      template<typename T, T*> struct A {};
      int dummy;
      A<int, &dummy> a;

See also issue 1322.

#### 314. `template` in base class specifier

Section: 14.2 [temp.names] Status: drafting Submitter: Mark Mitchell Date: 23 Aug 2001

The EDG front-end accepts:

    template <typename T>
    struct A {
      template <typename U>
      struct B {};
    };

    template <typename T>
    struct C : public A<T>::template B<T> {
    };

It rejects this code if the base-specifier is spelled `A<T>::B<T>`.

However, the grammar for a base-specifier does not allow the `template` keyword.

Suggested resolution:

It seems to me that a consistent approach to the solution that looks like it will be adopted for issue 180 (which deals with the `typename` keyword in similar contexts) would be to assume that `B` is a template if it is followed by a "<". After all, an expression cannot appear in this context.

Notes from the 4/02 meeting:

We agreed that `template` must be allowed in this context. The syntax needs to be changed. We also opened the related issue 343.

Additional note (August, 2010):

The same considerations apply to mem-initializer-ids, as noted in issue 1019.

#### 1478. `template` keyword for dependent template template arguments

Section: 14.2 [temp.names] Status: drafting Submitter: Johannes Schaub Date: 2012-03-10

According to 14.2 [temp.names] paragraph 4,

> When the name of a member template specialization appears after `.` or `->` in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1 [temp.dep.type]), the member template name must be prefixed by the keyword `template`.

In other words, the `template` keyword is only required when forming a template-id. However, current compilers reject an example like:

      template<typename T, template<typename> class U = T::X> struct A;

and require the `template` keyword before `X`. Should the rule be amended to require the `template` keyword in cases like this?

#### 1432. Newly-ambiguous variadic template expansions

Section: 14.5.3 [temp.variadic] Status: drafting Submitter: Daniel Krügler Date: 2011-12-17

With the new core rules in regard to variadic pack expansions the library specification of the traits template `common_type` is now broken, the reason is that it is defined as a series of specializations of the primary template

        template <class ...T>
        struct common_type;

The broken one is this pair:

      template <class T, class U>
      struct common_type<T, U> {
       typedef decltype(true ? declval<T>() : declval<U>()) type;
      };

      template <class T, class U, class... V>
      struct common_type<T, U, V...> {
       typedef typename common_type<typename common_type<T, U>::type, V...>::type type;
      };

With the new rules both specializations would now be ambiguous for an instantiation like `common_type<X, Y>`.

(See also issue 1395.)

Notes from the October, 2012 meeting:

It is possible that 14.5.5.2 [temp.class.order] may resolve this problem.

#### 1545. `friend` function templates defined in class templates

Section: 14.5.4 [temp.friend] Status: drafting Submitter: Daniel Krügler Date: 2012-08-25

The status of an example like the following is not clear:

       template<class> struct x {
         template<class T>
         friend bool operator==(x<T>, x<T>) { return false; }
      };

      int main() {
        x<int> x1;
        x<double> x2;
        x1 == x1;
        x2 == x2;
      }

Such a `friend` definition is permitted by 14.5.4 [temp.friend] paragraph 2:

> A friend function template may be defined within a class or class template...

Paragraph 4 appears to be related, but deals only with friend functions, not friend function templates:

> When a function is defined in a friend function declaration in a class template, the function is instantiated when the function is odr-used. The same restrictions on multiple declarations and definitions that apply to non-template function declarations and definitions also apply to these implicit definitions.

#### 1315. Restrictions on non-type template arguments in partial specializations

Section: 14.5.5 [temp.class.spec] Status: drafting Submitter: Johannes Schaub Date: 2011-05-12

The rationale for the restriction in 14.5.5 [temp.class.spec] paragraph 8, first bullet is not clear:

- A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier. [Example:

      template <int I, int J> struct A {};
      template <int I> struct A<I+5, I*2> {}; // error
      template <int I, int J> struct B {};
      template <int I> struct B<I, I> {};     // OK

—end example]

In the example, it's clear that `I` is non-deducible, but this rule prevents plausible uses like:

      template <int I, int J> struct A {};
      template <int I> struct A<I, I*2> {};

#### 549. Non-deducible parameters in partial specializations

Section: 14.5.5.1 [temp.class.spec.match] Status: drafting Submitter: Martin Sebor Date: 18 November 2005

In the following example, the template parameter in the partial specialization is non-deducible:

        template <class T> struct A { typedef T U; };
        template <class T> struct C { };
        template <class T> struct C<typename A<T>::U> { };

Several compilers issue errors for this case, but there appears to be nothing in the Standard that would make this ill-formed; it simply seems that the partial specialization will never be matched, so the primary template will be used for all specializations. Should it be ill-formed?

(See also issue 1246.)

Notes from the April, 2006 meeting:

It was noted that there are similar issues for constructors and conversion operators with non-deducible parameters, and that they should probably be dealt with similarly.

#### 1446. Member function with no ref-qualifier and non-member function with rvalue reference

Section: 14.5.6.2 [temp.func.order] Status: drafting Submitter: Jason Merrill Date: 2012-02-07

A member function with no ref-qualifier can be called for a class prvalue, as can a non-member function whose first parameter is an rvalue reference to that class type. However, 14.5.6.2 [temp.func.order] does not handle this case.

#### 1286. Equivalence of alias templates

Section: 14.5.7 [temp.alias] Status: drafting Submitter: Gabriel Dos Reis Date: 2011-04-03

Issue 1244 was resolved by changing the example in 14.4 [temp.type] paragraph 1 from

      template<template<class> class TT> struct X { };
      template<class> struct Y { };
      template<class T> using Z = Y<T>;
      X<Y> y;
      X<Z> z;

to

      template<class T> struct X { };
      template<class> struct Y { };
      template<class T> using Z = Y<T>;
      X<Y<int> > y;
      X<Z<int> > z;

In fact, the original intent was that the example should have been correct as written; however, the normative wording to make it so was missing. The current wording of 14.5.7 [temp.alias] deals only with the equivalence of a specialization of an alias template with the type-id after substitution. Wording needs to be added specifying under what circumstances an alias template itself is equivalent to a class template.

Proposed resolution (September, 2012):

1. Add the following as a new paragraph following 14.5.7 [temp.alias] paragraph 2:

> When the type-id in the declaration of alias template (call it `A`) consists of a simple-template-id in which the template-argument-list consists of a list of identifiers naming each template-parameter of `A` exactly once in the same order in which they appear in `A`'s template-parameter-list, the alias template is equivalent to the template named in the simple-template-id (call it `T`) if `A` and `T` have the same number of template-parameters. [Footnote: This rule is transitive: if an alias template `A` is equivalent to another alias template `B` that is equivalent to a class template `C`, then `A` is also equivalent to `C`, and `A` and `B` are also equivalent to each other. —end footnote] [Example:

>       template<typename T, U = T> struct A;

>       template<typename V, typename W>
>         using B = A<V, W>;                // equivalent to A

>       template<typename V, typename W>
>         using C = A<V>;                   // not equivalent to A:
>                                           // not all parameters used

>       template<typename V>
>         using D = A<V>;                   // not equivalent to A:
>                                           // different number of parameters

>       template<typename V, typename W>
>         using E = A<W, V>;                // not equivalent to A:
>                                           // template-arguments in wrong order

>       template<typename V, typename W = int>
>         using F = A<V, W>;                // equivalent to A:
>                                           // default arguments not considered

>       template<typename V, typename W>
>         using G = A<V, W>;                // equivalent to A and B

>       template<typename V, typename W>
>         using H = E<V, W>;                // equivalent to E

>       template<typename V, typename W>
>         using I = A<V, typename W::type>; // not equivalent to A:
>                                           // argument not identifier

> —end example]

2. Change 14.4 [temp.type] paragraph 1 as follows:

> Two template-ids refer to the same class or function if

> - ...

> - their corresponding template template-arguments refer to the same or equivalent (14.5.7 [temp.alias]) templates.

> [Example:

> ...declares `x2` and `x3` to be of the same type. Their type differs from the types of `x1` and `x4`.

>       template<class T template<class> class TT> struct X { };
>       template<class> struct Y { };
>       template<class T> using Z = Y<T>;
>       X<Y<int> Y> y;
>       X<Z<int> Z> z;

> declares `y` and `z` to be of the same type. —end example]

#### 1349. Consistency of alias template redeclarations

Section: 14.5.7 [temp.alias] Status: drafting Submitter: Richard Smith Date: 2011-08-16

There appears to be no requirement that a redeclaration of an alias template must be equivalent to the earlier one. An alias-declaration is not a definition (3.1 [basic.def] paragraph 2), so presumably an alias template declaration is also not a definition and thus the ODR does not apply.

#### 1430. Pack expansion into fixed alias template parameter list

Section: 14.5.7 [temp.alias] Status: drafting Submitter: Jason Merrill Date: 2011-12-13

Originally, a pack expansion could not expand into a fixed-length template parameter list, but this was changed in N2555. This works fine for most templates, but causes issues with alias templates.

In most cases, an alias template is transparent; when it's used in a template we can just substitute in the dependent template arguments. But this doesn't work if the template-id uses a pack expansion for non-variadic parameters. For example:

        template<class T, class U, class V>
        struct S {};

        template<class T, class V>
        using A = S<T, int, V>;

        template<class... Ts>
        void foo(A<Ts...>);

There is no way to express `A<Ts...>` in terms of `S`, so we need to hold onto the `A` until we have the `Ts` to substitute in, and therefore it needs to be handled in mangling.

Currently, EDG and Clang reject this testcase, complaining about too few template arguments for A. G++ did as well, but I thought that was a bug. However, on the ABI list John Spicer argued that it should be rejected.

(See also issue 1558.)

Notes from the October, 2012 meeting:

The consensus of CWG was that this usage should be prohibited, disallowing use of an alias template when a dependent argument can't simply be substituted directly into the type-id.

#### 1554. Access and alias templates

Section: 14.5.7 [temp.alias] Status: drafting Submitter: Jason Merrill Date: 2012-09-17

The interaction of alias templates and access control is not clear from the current wording of 14.5.7 [temp.alias]. For example:

      template <class T> using foo = typename T::foo;

      class B {
        typedef int foo;
        friend struct C;
      };

      struct C {
        foo<B> f;    // Well-formed?
      };

Is the substitution of `B::foo` for `foo<B>` done in the context of the befriended class `C`, making the reference well-formed, or is the access determined independently of the context in which the alias template specialization appears?

If the answer to this question is that the access is determined independently from the context, care must be taken to ensure that an access failure is still considered to be “in the immediate context of the function type” (14.8.2 [temp.deduct] paragraph 8) so that it results in a deduction failure rather than a hard error.

Notes from the October, 2012 meeting:

The consensus of CWG was that instantiation (lookup and access) for alias templates should be as for other templates, in the definition context rather than in the context where they are used. They should still be expanded immediately, however.

#### 1558. Unused arguments in alias template specializations

Section: 14.5.7 [temp.alias] Status: drafting Submitter: Nikolay Ivchenkov Date: 2012-09-19

The treatment of unused arguments in an alias template specialization is not specified by the current wording of 14.5.7 [temp.alias]. For example:

      #include <iostream>

      template <class T, class...>
        using first_of = T;

      template <class T>
        first_of<void, typename T::type> f(int)
          { std::cout << "1\n"; }

      template <class T>
        void f(...)
          { std::cout << "2\n"; }

      struct X { typedef void type; };

      int main() {
        f<X>(0);
        f<int>(0);
      }

Is the reference to `first_of<void, T::type>` with `T` being `int` equivalent to simply `void`, or is it a substitution failure?

(See also issues 1430, 1520, and 1554.)

Notes from the October, 2012 meeting:

The consensus of CWG was to treat this case as substitution failure.

#### 560. Use of the `typename` keyword in return types

Section: 14.6 [temp.res] Status: drafting Submitter: Greg Comeau Date: 11 February 2006

Consider the following example:

        template <class T> struct Outer {
            struct Inner {
                Inner* self();
            };
        };
        template <class T> Outer<T>::Inner*
            Outer<T>::Inner::self() { return this; }

According to 14.6 [temp.res] paragraph 3 (before the salient wording was inadvertently removed, see issue 559),

> A qualified-id that refers to a type and in which the nested-name-specifier depends on a template-parameter (14.6.2 [temp.dep]) but does not refer to a member of the current instantiation (14.6.2.1 [temp.dep.type]) shall be prefixed by the keyword `typename` to indicate that the qualified-id denotes a type, forming a typename-specifier.

Because `Outer<T>::Inner` is a member of the current instantiation, the Standard does not currently require that it be prefixed with `typename` when it is used in the return type of the definition of the `self()` member function. However, it is difficult to parse this definition correctly without knowing that the return type is, in fact, a type, which is what the `typename` keyword is for. Should the Standard be changed to require `typename` in such contexts?

#### 1271. Imprecise wording regarding dependent types

Section: 14.6 [temp.res] Status: drafting Submitter: Daveed Vandevoorde Date: 2011-03-24

According to 14.6 [temp.res] paragraph 3,

> When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1 [temp.dep.type]) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword `typename`, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type, the program is ill- formed.

The intent of the programmer cannot form the basis for a compiler determining whether to issue a diagnostic or not.

Suggested resolution:

> Let `N` be a qualified-id with a nested-name-specifier that denotes a dependent type. If `N` is not prefixed by the keyword `typename`, `N` shall refer to a member of the current instantiation or it shall not refer to a type.

> typename-specifier:
> `typename` nested-name-specifier identifier
> `typename` nested-name-specifier `template` opt simple-template-id

> If the qualified-id in a typename-specifier does not denote a type, the program is ill-formed.

(See also issues 590 and 591.)

#### 591. When a dependent base class is the current instantiation

Section: 14.6.2 [temp.dep] Status: drafting Submitter: James Widman Date: 24 August 2006

Is the following example well-formed?

        template<class T> struct A {
             typedef int M;
             struct B {
                 typedef void M;
                 struct C;
             };
        };

        template<class T> struct A<T>::B::C : A<T> {
             M  // A<T>::M or A<T>::B::M?
                 p[2];
        };

14.6.2 [temp.dep] paragraph 3 says the use of `M` should refer to `A<T>::B::M` because the base class `A<T>` is not searched because it's dependent. But in this case `A<T>` is also the current instantiation (14.6.2.1 [temp.dep.type]) so it seems like it should be searched.

Notes from the August, 2011 meeting:

The recent changes to the handling of the current instantiation may have sufficiently addressed this issue.

Additional note (September, 2012):

See also issue 1526 for additional analysis demonstrating that this issue is still current despite the changes to the description of the current instantiation. The status has consequently been changed back to "open" for further consideration.

#### 1292. Dependent calls with braced-init-lists containing a pack expansion

Section: 14.6.2 [temp.dep] Status: drafting Submitter: James Widman Date: 2011-04-10

The discussion of issue 1233 revealed that the dependency of function calls involving a braced-init-list containing a pack expansion is not adequately addressed by the existing wording.

#### 1309. Incorrect note regarding lookup of a member of the current instantiation

Section: 14.6.2.1 [temp.dep.type] Status: drafting Submitter: Johannes Schaub Date: 2011-05-05

The note in 14.6.2.1 [temp.dep.type] paragraph 7 reads,

> [Note: the result of name lookup differs only when the member of the current instantiation was found in a non-dependent base class of the current instantiation and a member with the same name is also introduced by the substitution for a dependent base class of the current instantiation. —end note]

However, this is not correct. Consider the following example:

      struct Y { int X; };

      template<typename T>
      struct A : Y {
       enum B : int;
       void f() { A::X; } // finds Y::X here!
      };

      template<typename T>
      enum A<T>::B : int {
       X // introduces member A::X into A<T>!
      };

      void g() { A<int> a; a.f(); }

`A::X` is a member of the current instantiation, so paragraph 7 requires it to be looked up again when instantiating and to give a diagnostic if the lookup differs from the lookup in the definition context. The note incorrectly indicates that this can only happen if the conflicting name was introduced by a dependent base class.

Proposed resolution (August, 2011):

Change 14.6.2.1 [temp.dep.type] paragraph 7 as follows:

> ...If the result of this lookup differs from the result of name lookup in the template definition context, name lookup is ambiguous. [Note: the result of name lookup differs only when the member of the current instantiation was found in a non-dependent base class of the current instantiation and a member with the same name is also introduced by the substitution for a dependent base class of the current instantiation. —end note] [Example:

>       struct A {
>         int m;
>       };

>       struct B {
>         int m;
>       };

>       template<typename T>
>       struct C : A, T {
>         int f() { return this->m; } // finds A::m in the template definition context
>       };

>       int g(C<B> cb) {
>         return cb.f();              // error: finds both A::m and B::m in the template instantiation context
>       }

> —end example]

Notes from the December, 2011 teleconference:

Changes to the exposition were suggested and the issue returned to "drafting" status.

#### 1390. Dependency of alias template specializations

Section: 14.6.2.1 [temp.dep.type] Status: drafting Submitter: Johannes Schaub Date: 2011-09-04

According to 14.6.2.1 [temp.dep.type] paragraph 8, a type is dependent (among other things) if it is

- a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent

This applies to alias template specializations, even if the resulting type does not depend on the template argument:

        struct B { typedef int type; };
        template<typename> using foo = B;
        template<typename T> void f() {
          foo<T>::type * x;  //error: typename required
        }

Is a change to the rules for cases like this warranted?

Notes from the October, 2012 meeting:

CWG agreed that no `typename` should be required in this case. In some ways, an alias template specialization is like the current instantiation and can be known at template definition time.

#### 1524. Incompletely-defined class template base

Section: 14.6.2.1 [temp.dep.type] Status: drafting Submitter: Jason Merrill Date: 2012-07-17

The correct handling of an example like the following is unclear:

      template<typename T> struct A {
        struct B: A { };
      };

A type used as a base must be complete (10 [class.derived] paragraph 2). The fact that the base class in this example is the current instantiation could be interpreted as indicating that it should be available for lookup, and thus the normal rule should apply, as members declared after the nested class would not be visible.

On the other hand, 14.6.2 [temp.dep] paragraph 3 says,

> In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

This wording refers not to a dependent type, which would permit lookup in the current instantiation, but simply to a type that “depends on a template-parameter,” and the current instantiation is such a type.

Implementations vary on the handling of this example.

(See also issue 1526 for another case related to the distinction between a “dependent type” and a “type that depends on a template-parameter.”)

Notes from the October, 2012 meeting:

CWG determined that the example should be ill-formed.

#### 2. How can dependent names be used in member declarations that appear outside of the class template definition?

Section: 14.6.4 [temp.dep.res] Status: drafting Submitter: unknown Date: unknown

        template <class T> class Foo {

           public:
           typedef int Bar;
           Bar f();
        };
        template <class T> typename Foo<T>::Bar Foo<T>::f() { return 1;}
                           --------------------

In the class template definition, the declaration of the member function is interpreted as:

       int Foo<T>::f();

In the definition of the member function that appears outside of the class template, the return type is not known until the member function is instantiated. Must the return type of the member function be known when this out-of-line definition is seen (in which case the definition above is ill-formed)? Or is it OK to wait until the member function is instantiated to see if the type of the return type matches the return type in the class template definition (in which case the definition above is well-formed)?

Suggested resolution: (John Spicer)

My opinion (which I think matches several posted on the reflector recently) is that the out-of-class definition must match the declaration in the template. In your example they do match, so it is well formed.

I've added some additional cases that illustrate cases that I think either are allowed or should be allowed, and some cases that I don't think are allowed.

        template <class T> class A { typedef int X; };

        template <class T> class Foo {
         public:
           typedef int Bar;
           typedef typename A<T>::X X;
           Bar f();
           Bar g1();
           int g2();
           X h();
           X i();
           int j();
         };

         // Declarations that are okay
         template <class T> typename Foo<T>::Bar Foo<T>::f()
                                                         { return 1;}
         template <class T> typename Foo<T>::Bar Foo<T>::g1()
                                                         { return 1;}
         template <class T> int Foo<T>::g2() { return 1;}
         template <class T> typename Foo<T>::X Foo<T>::h() { return 1;}

         // Declarations that are not okay
         template <class T> int Foo<T>::i() { return 1;}
         template <class T> typename Foo<T>::X Foo<T>::j() { return 1;}

In general, if you can match the declarations up using only information from the template, then the declaration is valid.

Declarations like `Foo::i` and `Foo::j` are invalid because for a given instance of `A<T>`, `A<T>::X` may not actually be int if the class is specialized.

This is not a problem for `Foo::g1` and `Foo::g2` because for any instance of `Foo<T>` that is generated from the template you know that Bar will always be int. If an instance of `Foo` is specialized, the template member definitions are not used so it doesn't matter whether a specialization defines `Bar` as int or not.

#### 287. Order dependencies in template instantiation

Section: 14.6.4.1 [temp.point] Status: drafting Submitter: Martin Sebor Date: 17 May 2001

Implementations differ in their treatment of the following code:

        template <class T>
        struct A {
    	typename T::X x;
        };

        template <class T>
        struct B {
    	typedef T* X;
    	A<B> a;
        };

        int main ()
        {
    	B<int> b;
        }

Some implementations accept it. At least one rejects it because the instantiation of `A<B<int> >` requires that `B<int>` be complete, and it is not at the point at which `A<B<int> >` is being instantiated.

Erwin Unruh:

In my view the programm is ill-formed. My reasoning:

- you need a complete type `B<int>` because you declare a variable in `main`
- `B<int>` contains a member of type `A<B<int> >`, so you need that complete.
- `A<B<int> >` tries to access `B<int>::X`, which in turn needs `B<int>` being complete.

So each class needs the other to be complete.

The problem can be seen much easier if you replace the typedef with

        typedef T (*X) [sizeof(B::a)];

Now you have a true recursion. The compiler cannot easily distinguish between a true recursion and a potential recursion.

John Spicer:

Using a class to form a qualified name does not require the class to be complete, it only requires that the named member already have been declared. In other words, this kind of usage is permitted:

        class A {
            typedef int B;
            A::B ab;
        };

In the same way, once `B` has been declared in `A`, it is also visible to any template that uses `A` through a template parameter.

The standard could be more clear in this regard, but there are two notes that make this point. Both 3.4.3.1 [class.qual] and 5.1.1 [expr.prim.general] paragraph 7 contain a note that says "a class member can be referred to using a qualified-id at any point in its potential scope (3.3.7 [basic.scope.class])." A member's potential scope begins at its point of declaration.

In other words, a class has three states: incomplete, being completed, and complete. The standard permits a qualified name to be used once a name has been declared. The quotation of the notes about the potential scope was intended to support that.

So, in the original example, class `A` does not require the type of `T` to be complete, only that it have already declared a member `X`.

Bill Gibbons:

The template and non-template cases are different. In the non-template case the order in which the members become declared is clear. In the template case the members of the instantiation are conceptually all created at the same time. The standard does not say anything about trying to mimic the non-template case during the instantiation of a class template.

Mike Miller:

I think the relevant specification is 14.6.4.1 [temp.point] paragraph 3, dealing with the point of instantiation:

> For a class template specialization... if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.

That means that the point of instantiation of `A<B<int> >` is before that of `B<int>`, not in the middle of `B<int>` after the declaration of `B::X`, and consequently a reference to `B<int>::X` from `A<B<int> >` is ill-formed.

To put it another way, I believe John's approach requires that there be an instantiation stack, with the results of partially-instantiated templates on the stack being available to instantiations above them. I don't think the Standard mandates that approach; as far as I can see, simply determining the implicit instantiations that need to be done, rewriting the definitions at their respective points of instantiation with parameters substituted (with appropriate "forward declarations" to allow for non-instantiating references), and compiling the result normally should be an acceptable implementation technique as well. That is, the implicit instantiation of the example (using, e.g., `B_int` to represent the generated name of the `B<int>` specialization) could be something like

            struct B_int;

            struct A_B_int {
                B_int::X x;    // error, incomplete type
            };

            struct B_int {
                typedef int* X;
                A_B_int a;
            };

Notes from 10/01 meeting:

This was discussed at length. The consensus was that the template case should be treated the same as the non-template class case it terms of the order in which members get declared/defined and classes get completed.

Proposed resolution:

In 14.6.4.1 [temp.point] paragraph 3 change:

> the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.

To:

> the point of instantiation is the same as the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the nearest enclosing declaration. [Note: The point of instantiation is still at namespace scope but any declarations preceding the point of instantiation, even if not at namespace scope, are considered to have been seen.]

Add following paragraph 3:

> If an implicitly instantiated class template specialization, class member specialization, or specialization of a class template references a class, class template specialization, class member specialization, or specialization of a class template containing a specialization reference that directly or indirectly caused the instantiation, the requirements of completeness and ordering of the class reference are applied in the context of the specialization reference.

and the following example

      template <class T> struct A {
              typename T::X x;
      };

      struct B {
              typedef int X;
              A<B> a;
      };

      template <class T> struct C {
              typedef T* X;
              A<C> a;
      };

      int main ()
      {
              C<int> c;
      }

Notes from the October 2002 meeting:

This needs work. Moved back to drafting status.

See also issues 595 and 1330.

#### 1258. “Instantiation context” differs from dependent lookup rules

Section: 14.6.4.1 [temp.point] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-10

C++11 expanded the lookup rules for dependent function calls (14.6.4.2 [temp.dep.candidate] paragraph 1 bullet 2) to include functions with internal linkage; previously only functions with external linkage were considered. However, 14.6.4.1 [temp.point] paragraph 6 still says,

> The instantiation context of an expression that depends on the template arguments is the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.

Presumably this wording was overlooked and should be harmonized with the new specification.

#### 1253. Generic non-template members

Section: 14.7 [temp.spec] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-06

Many statements in the Standard apply only to templates, for example, 14.6 [temp.res] paragraph 8:

> If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required.

This clearly should apply to non-template member functions of class templates, not just to templates per se. Terminology should be established to refer to these generic entities that are not actually templates.

Additional notes (August, 2012):

Among the generic entities that should be covered by such a term are default function arguments, as they can be instantiated independently. If issue 1330 is resolved as expected, exception-specifications should also be covered by the same term.

See also issue 1484.

#### 212. Implicit instantiation is not described clearly enough

Section: 14.7.1 [temp.inst] Status: drafting Submitter: Christophe de Dinechin Date: 7 Mar 2000

Three points have been raised where the wording in 14.7.1 [temp.inst] may not be sufficiently clear.

1. In paragraph 4, the statement is made that

   > A class template specialization is implicitly instantiated... if the completeness of the class type affects the semantics of the program...

   It is not clear what it means for the "completeness... [to affect] the semantics." Consider the following example:

               template<class T> struct A;
               extern A<int> a;

               void *foo() { return &a; }

               template<class T> struct A
               {
               #ifdef OPTION
                       void *operator &() { return 0; }
               #endif
               };

   The question here is whether it is necessary for template class `A` to declare an `operator &` for the semantics of the program to be affected. If it does not do so, the meaning of `&a` will be the same whether the class is complete or not and thus arguably the semantics of the program are not affected.

   Presumably what was intended is whether the presence or absence of certain member declarations in the template class might be relevant in determining the meaning of the program. A clearer statement may be desirable.

2. Paragraph 5 says,

   > If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place.

   The intent of this wording, as illustrated in the example in that paragraph, is to allow a "smart" implementation not to instantiate class templates if it can determine that such an instantiation will not affect the result of overload resolution, even though the algorithm described in clause 13 [over] requires that all the viable functions be enumerated, including functions that might be found as members of specializations.

   Unfortunately, the looseness of the wording allowing this latitude for implementations makes it unclear what "the overload resolution process" is — is it the algorithm in 13 [over] or something else? — and what "the correct function" is.

3. According to paragraph 6,

   > If an implicit instantiation of a class template specialization is required and the template is declared but not defined, the program is ill-formed.

   Here, it is not clear what conditions "require" an implicit instantiation. From the context, it would appear that the intent is to refer to the conditions in paragraph 4 that cause a specialization to be instantiated.

   This interpretation, however, leads to different treatment of template and non-template incomplete classes. For example, by this interpretation,

           class A;
           template <class T> struct TA;
           extern A a;
           extern TA<int> ta;

           void f(A*);
           void f(TA<int>*);

           int main()
           {
               f(&a);    // well-formed; undefined if A
                         // has operator &() member
               f(&ta);   // ill-formed: cannot instantiate
           }

   A different approach would be to understand "required" in paragraph 6 to mean that a complete type is required in the expression. In this interpretation, if an incomplete type is acceptable in the context and the class template definition is not visible, the instantiation is not attempted and the program is well-formed.

   The meaning of "required" in paragraph 6 must be clarified.

(See also issues 204 and 63.)

Notes on 10/01 meeting:

It was felt that item 1 is solved by addition of the word "might" in the resolution for issue 63; item 2 is not much of a problem; and item 3 could be solved by changing "required" to "required to be complete".

#### 1396. Deferred instantiation and checking of non-static data member initializers

Section: 14.7.1 [temp.inst] Status: drafting Submitter: Jason Merrill Date: 2011-09-22

Non-static data member initializers get the same late parsing as member functions and default arguments, but are they also instantiated as needed like them? And when is their validity checked?

Notes from the October, 2012 meeting:

CWG agreed that non-static data member initializers should be handled like default arguments.

#### 529. Use of `template<>` with “explicitly-specialized” class templates

Section: 14.7.3 [temp.expl.spec] Status: drafting Submitter: James Widman Date: 16 August 2005

Paragraph 17 of 14.7.3 [temp.expl.spec] says,

> A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a `template<>` for each enclosing class template that is explicitly specialized.

This is curious, because paragraph 3 only allows explicit specialization of members of implicitly-instantiated class specializations, not explicit specializations. Furthermore, paragraph 4 says,

> Definitions of members of an explicitly specialized class are defined in the same manner as members of normal classes, and not using the explicit specialization syntax.

Paragraph 18 provides a clue for resolving the apparent contradiction:

> In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. In such explicit specialization declaration, the keyword `template` followed by a template-parameter-list shall be provided instead of the `template<>` preceding the explicit specialization declaration of the member.

It appears from this and the following example that the phrase “explicitly specialized” in paragraphs 17 and 18, when referring to enclosing class templates, does not mean that explicit specializations have been declared for them but that their names in the qualified-id are followed by template argument lists. This terminology is confusing and should be changed.

Proposed resolution (October, 2005):

1. Change 14.7.3 [temp.expl.spec] paragraph 17 as indicated:

> A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a `template<>` for each enclosing class template that is explicitly specialized specialization. [Example:...

2. Change 14.7.3 [temp.expl.spec] paragraph 18 as indicated:

> In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well that is, the template-id naming the template may be composed of template parameter names rather than template-arguments. In For each unspecialized template in such an explicit specialization declaration, the keyword `template` followed by a template-parameter-list shall be provided instead of the `template<>` preceding the explicit specialization declaration of the member. The types of the template-parameters in the template-parameter-list shall be the same as those specified in the primary template definition. In such declarations, an unspecialized template-id shall not precede the name of a template specialization in the qualified-id naming the member. [Example:...

Notes from the April, 2006 meeting:

The revised wording describing “unspecialized” templates needs more work to ensure that the parameter names in the template-id are in the correct order; the distinction between template arguments and parameters is also probably not clear enough. It might be better to replace this paragraph completely and avoid the “unspecialized” wording altogether.

Proposed resolution (February, 2010):

1. Change 14.7.3 [temp.expl.spec] paragraph 17 as follows:

> A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a `template<>` for each enclosing class template that is explicitly specialized specialization. [Example:...

2. Change 14.7.3 [temp.expl.spec] paragraph 18 as follows:

> In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. In such explicit specialization declaration, the keyword `template` followed by a template-parameter-list shall be provided instead of the `template<>` preceding the explicit specialization declaration of the member. The types of the template-parameters in the template-parameter-list shall be the same as those specified in the primary template definition. that is, the corresponding template prefix may specify a template-parameter-list instead of `template<>` and the template-id naming the template be written using those template-parameters as template-arguments. In such a declaration, the number, kinds, and types of the template-parameters shall be the same as those specified in the primary template definition, and the template-parameters shall be named in the template-id in the same order that they appear in the template-parameter-list. An unspecialized template-id shall not precede the name of a template specialization in the qualified-id naming the member. [Example:...

#### 1172. “instantiation-dependent” constructs

Section: 14.8.2 [temp.deduct] Status: drafting Submitter: Adamczyk Date: 2010-08-05

There are certain constructs that are not covered by the existing categories of “type dependent” and “value dependent.” For example, the expression `sizeof(sizeof(T()))` is neither type-dependent nor value-dependent, but its validity depends on whether `T` can be value-constructed. We should be able to overload on such characteristics and select via deduction failure, but we need a term like “instantiation-dependent” to describe these cases in the Standard. The phrase “expression involving a template parameter” seems to come pretty close to capturing this idea.

Notes from the November, 2010 meeting:

The CWG favored extending the concepts of “type-dependent” and “value-dependent” to cover these additional cases, rather than adding a new concept.

Notes from the March, 2011 meeting:

The CWG reconsidered the direction from the November, 2010 meeting, as it would make more constructs dependent, thus requiring more `template` and `typename` keywords, resulting in worse error messages, etc.

Notes from the August, 2011 meeting:

The following example (from issue 1273) was deemed relevant for this issue:

        template <class T> struct C;

        class A {
           int i;
           friend struct C<int>;
        } a;

        class B {
           int i;
           friend struct C<float>;
        } b;

        template <class T>
        struct C {
           template <class U> decltype (a.i) f() { } // #1
           template <class U> decltype (b.i) f() { } // #2
        };

        int main() {
           C<int>().f<int>();     // calls #1
           C<float>().f<float>(); // calls #2
        }

#### 1322. Function parameter type decay in templates

Section: 14.8.2 [temp.deduct] Status: drafting Submitter: Jason Merrill Date: 2011-05-19

The discussion of issue 1001 seemed to have settled on the approach of doing the 8.3.5 [dcl.fct] transformations immediately to the function template declaration, so that the original form need not be remembered. However, the example in 14.8.2 [temp.deduct] paragraph 8 suggests otherwise:

      template <class T> int f(T[5]);
      int I = f<int>(0);
      int j = f<void>(0); // invalid array

One way that might be addressed would be to separate the concepts of the type of the template that participates in overload resolution and function matching from the type of the template that is the source for template argument substitution. (See also the example in paragraph 3 of the same section.)

Notes, January, 2012:

#### 1513. `initializer_list` deduction failure

Section: 14.8.2.1 [temp.deduct.call] Status: drafting Submitter: Steve Adamczyk Date: 2012-06-28

According to 14.8.2.1 [temp.deduct.call] paragraph 1,

> If removing references and cv-qualifiers from `P` gives `std::initializer_list<P'>` for some `P'` and the argument is an initializer list (8.5.4 [dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking `P'` as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5 [temp.deduct.type]).

It is not entirely clear whether the deduction for an initializer list meeting a `std::initializer_list<T>` is a recursive subcase, or part of the primary deduction. A relevant question is: if the deduction on that part fails, does the entire deduction fail, or is the parameter to be considered non-deduced?

Notes from the October, 2012 meeting:

CWG determined that the entire deduction fails in this case.

#### 1486. Base-derived conversion in member pointer deduction

Section: 14.8.2.2 [temp.deduct.funcaddr] Status: drafting Submitter: John Spicer Date: 2012-03-26

The rules for deducing template arguments when taking the address of a function template in 14.8.2.2 [temp.deduct.funcaddr] do not appear to allow for a base-to-derived conversion in a case like:

      struct Base {
        template<class U> void f(U);
      };

      struct Derived : Base { };

      int main() {
        void (Derived::*pmf)(int) = &Derived::f;
      }

Most implementations appear to allow this adjustment, however.

#### 1395. Partial ordering of variadic templates reconsidered

Section: 14.8.2.5 [temp.deduct.type] Status: drafting Submitter: John Spicer Date: 2011-09-21

The resolution of issue 692 (found in document N3281) made the following example ambiguous and thus ill-formed:

        template<class T>
        void print(ostream &os, const T &t) {
            os << t;
        }

        template <class T, class... Args>
        void print(ostream &os, const T &t, const Args&... rest) {
            os << t << ", ";
            print(os, rest...);
        }

        int main() {
            print(cout, 42);
            print(cout, 42, 1.23);
        }

This pattern seems fairly intuitive; is it reason to reconsider or modify the outcome of issue 692?

(See also issue 1432.)

Notes from the October, 2012 meeting:

CWG agreed that the example should be accepted, handling this case as a late tiebreaker, preferring an omitted parameter over a parameter pack.

#### 1424. When must sub-object destructors be accessible?

Section: 15.2 [except.ctor] Status: drafting Submitter: Daniel Krügler Date: 2011-12-07

The current specification does not appear to say whether an implementation is permitted/required/forbidden to complain when a sub-object's destructor is inaccessible. In particular, if there is no possibility for an exception to be thrown following a given sub-object's construction, should an implementation issue an error if that sub-object's destructor is inaccessible?

Proposed resolution (February, 2012):

1. Change 3.2 [basic.def.odr] paragraph 2 as follows:

> ...A destructor for a class is odr-used as specified in if it is potentially invoked (12.4 [class.dtor]).

2. Change 5.3.4 [expr.new] paragraph 17 as follows:

> If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function (12.5 [class.free]), and the constructor (12.1 [class.ctor]). If the new expression new-expression creates an array of objects of class type, access and ambiguity control are done for the destructor is potentially invoked (12.4 [class.dtor]).

3. Change 12.4 [class.dtor] paragraph 11 as follows:

> Destructors are A destructor is invoked implicitly

> - for a constructed objects with static storage duration (3.7.1 [basic.stc.static]) at program termination (3.6.3 [basic.start.term]),

> - for a constructed objects with thread storage duration (3.7.2 [basic.stc.thread]) at thread exit,

> - for a constructed objects with automatic storage duration (3.7.3 [basic.stc.auto]) when the block in which an object is created exits (6.7 [stmt.dcl]),

> - for a constructed temporary objects when the its lifetime of a temporary object ends (12.2 [class.temporary]),.

> - for constructed objects allocated by a new-expression (5.3.4 [expr.new]), through use of a delete-expression (5.3.5 [expr.delete]),

> - in several situations due to the handling of exceptions (15.3 [except.handle]).

> In each case, the context of the invocation is the context of the construction of the object. A destructor is also invoked implicitly through use of a delete-expression (5.3.5 [expr.delete]) for a constructed object allocated by a new-expression (5.3.4 [expr.new]); the context of the invocation is the delete-expression. [Note: An array of class type contains several subobjects for each of which the destructor is invoked. —end note] A destructor can also be invoked explicitly. A destructor is potentially invoked if it is invoked or as specified in 5.3.4 [expr.new] and 12.6.2 [class.base.init]. A program is ill-formed if an object of class type or array thereof is declared and the destructor for the class is not accessible at the point of the declaration a destructor that is potentially invoked is deleted or not accessible from the context of the invocation. Destructors can also be invoked explicitly.

4. Add the following as a new paragraph following 12.6.2 [class.base.init] paragraph 9:

> If a given non-static data member has both...

> In a non-delegating constructor, the destructor for each direct or virtual base class and for each non-static data member of class type is potentially invoked (12.4 [class.dtor]). [Note: This provision ensures that destructors can be called for fully-constructed sub-objects in case an exception is thrown (15.2 [except.ctor]). —end note]

> In a non-delegating constructor, initialization proceeds...

#### 1436. Interaction of constant expression changes with preprocessor expressions

Section: 16.1 [cpp.cond] Status: drafting Submitter: Richard Smith Date: 2012-01-02

It appears that some of the recent changes to the description of constant expressions have allowed constructs into preprocessor expressions that do not belong there. Some changes are required to restrict the current capabilities of constant expressions to what is intended to be allowed in preprocessor expressions.

Proposed resolution (February, 2012):

1. Change 16.1 [cpp.cond] paragraph 2 as follows:

> Each preprocessing token that remains (in the list of preprocessing tokens that will become the controlling expression) after all macro replacements have occurred shall be in the lexical form of a token (2.7 [lex.token]). Any such token that is a literal (2.14.1 [lex.literal.kinds]) shall be an integer-literal, a character-literal, or a boolean-literal.

2. Change 16.1 [cpp.cond] paragraph 4 as follows:

> ...using arithmetic that has at least the ranges specified in 18.3 [support.limits]. The only operators permitted in the controlling constant expression are `?:`, `||`, `&&`, `|`, `^`, `&`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `<<`, `>>`, `-`, `+`, `*`, `/`, `%`, `!`, and `~`. For the purposes of this token conversion...

#### 1335. Stringizing, extended characters, and universal-character-names

Section: 16.3.2 [cpp.stringize] Status: drafting Submitter: Johannes Schaub Date: 2011-07-03

When a string literal containing an extended character is stringized (16.3.2 [cpp.stringize]), the result contains a universal-character-name instead of the original extended character. The reason is that the extended character is translated to a universal-character-name in translation phase 1 (2.2 [lex.phases]), so that the string literal `"@"` (where `@` represents an extended character) becomes `"\uXXXX"`. Because the preprocessing token is a string literal, when the stringizing occurs in translation phase 4, the `\` is doubled, and the resulting string literal is `"\"\\uXXXX\""`. As a result, the universal-character-name is not recognized as such when the translation to the execution character set occurs in translation phase 5. (Note that phase 5 translation does occur if the stringized extended character does not appear in a string literal.) Existing practice appears to ignore these rules and preserve extended characters in stringized string literals, however.

See also issue 578.

#### 1279. Additional differences between C++ 2003 and C++ 2011

Section: C.2 [diff.cpp03] Status: drafting Submitter: Nikolay Ivchenkov Date: 2011-03-27

A number of differences between C++03 and C++11 were omitted from C.2 [diff.cpp03]:

- New keywords. Although these are said in C.2.1 [diff.cpp03.lex] only to invalidate C++03 code, they can also change the meaning, e.g., `thread_local x(y)`, which would declare a variable `thread_local` initialized with `y` in C++03 and a thread-local variable `y` in C++11.

- New deduction rules.

- Removal of the deprecated string literal conversion.

- When a `friend` function defined in a class template is actually defined (i.e., with each instantiation or only when odr-used).

- Removal of access declarations.

- Use of the injected-class-name of a class template as a template template-argument.

Additional note (January, 2012):

In addition to the items previously mentioned, access declarations were removed from C++11 but are not mentioned in C.2 [diff.cpp03].

Proposed (partial) resolution (February, 2012):

Add the following as a new section in C.2 [diff.cpp03]:

> C.2.5 Clause 11 [class.access]: member access control | pdiff.cpp03.class.access

> Change: Remove access declarations.

> Rationale: Removal of feature deprecated since C++ 1998.

> Effect on original feature: Valid C++ 2003 code that uses access declarations is ill-formed in this International Standard. Instead, using-declarations (7.3.3 [namespace.udecl]) can be used.

### Issues with "Open" Status

#### 916. Does a reference type have a destructor?

Section: _N2914_.14.10.2.1 [concept.map.fct] Status: open Submitter: James Widman Date: 12 June, 2009

Is the following well-formed?

        auto concept HasDestructor<typename T> {
          T::~T();
        }

        concept_map HasDestructor<int&> { }

According to _N2914_.14.10.2.1 [concept.map.fct] paragraph 4, the destructor requirement in the concept map results in an expression `x.~X()`, where `X` is the type `int&`. According to 5.2.4 [expr.pseudo], this expression is ill-formed because the object type and the type-name must be the same type, but the object type cannot be a reference type (references are dropped from types used in expressions, 5 [expr] paragraph 5).

It is not clear whether this should be addressed by changing 5.2.4 [expr.pseudo] or _N2914_.14.10.2.1 [concept.map.fct].

#### 783. Definition of “argument”

Section: 1.3 [intro.defs] Status: open Submitter: UK Date: 3 March, 2009
N2800 comment UK 3

The definition of an argument does not seem to cover many assumed use cases, and we believe that is not intentional. There should be answers to questions such as: Are lambda-captures arguments? Are type names in a throw-spec arguments? “Argument” to casts, typeid, alignof, alignas, decltype and sizeof? why in x[arg] arg is not an argument, but the value forwarded to operator[]() is? Does not apply to operators as call-points not bounded by parentheses? Similar for copy initialization and conversion? What are deduced template “arguments?” what are “default arguments?” can attributes have arguments? What about concepts, requires clauses and concept_map instantiations? What about user-defined literals where parens are not used?

#### 949. Requirements for freestanding implementations

Section: 1.4 [intro.compliance] Status: open Submitter: Detlef Vollman Date: 2 August, 2009

According to 1.4 [intro.compliance] paragraph 7,

> A freestanding implementation is one in which execution may take place without the benefit of an operating system, and has an implementation-defined set of libraries that includes certain language-support libraries (17.6.1.3 [compliance]).

This definition links two relatively separate topics: the lack of an operating system and the minimal set of libraries. Furthermore, 3.6.1 [basic.start.main] paragraph 1 says:

> [Note: in a freestanding environment, start-up and termination is implementation-defined; start-up contains the execution of constructors for objects of namespace scope with static storage duration; termination contains the execution of destructors for objects with static storage duration. —end note]

It would be helpful if the two characteristics (lack of an operating system and restricted set of libraries) were named separately and if these statements were clarified to identify exactly what is implementation-defined.

Notes from the October, 2009 meeting:

The CWG felt that it needed a specific proposal in a paper before attempting to resolve this issue.

#### 698. The definition of “sequenced before” is too narrow

Section: 1.9 [intro.execution] Status: open Submitter: Jens Maurer Date: 13 July, 2008

According to 1.9 [intro.execution] paragraph 14, “sequenced before” is a relation between “evaluations.” However, 3.6.3 [basic.start.term] paragraph 3 says,

> If the completion of the initialization of a non-local object with static storage duration is sequenced before a call to `std::atexit` (see `<cstdlib>`, 18.5 [support.start.term]), the call to the function passed to `std::atexit` is sequenced before the call to the destructor for the object. If a call to `std::atexit` is sequenced before the completion of the initialization of a non-local object with static storage duration, the call to the destructor for the object is sequenced before the call to the function passed to `std::atexit`. If a call to `std::atexit` is sequenced before another call to `std::atexit`, the call to the function passed to the second `std::atexit` call is sequenced before the call to the function passed to the first `std::atexit` call.

Except for the calls to `std::atexit`, these events do not correspond to “evaluation” of expressions that appear in the program. If the “sequenced before” relation is to be applied to them, a more comprehensive definition is needed.

#### 578. Phase 1 replacement of characters with universal-character-names

Section: 2.2 [lex.phases] Status: open Submitter: Martin Vejnár Date: 7 May 2006

According to 2.2 [lex.phases] paragraph 1, in translation phase 1,

> Any source file character not in the basic source character set (2.3 [lex.charset]) is replaced by the universal-character-name that designates that character.

If a character that is not in the basic character set is preceded by a backslash character, for example

        "\á"

the result is equivalent to

        "\\u00e1"

that is, a backslash character followed by the spelling of the universal-character-name. This is different from the result in C99, which accepts characters from the extended source character set without replacing them with universal-character-names.

See also issue 1335.

#### 1403. Universal-character-names in comments

Section: 2.8 [lex.comment] Status: open Submitter: David Krauss Date: 2011-10-05

According to 2.3 [lex.charset] paragraph 2,

> If the hexadecimal value for a universal-character-name corresponds to a surrogate code point (in the range 0xD800-0xDFFF, inclusive), the program is ill-formed. Additionally, if the hexadecimal value for a universal-character-name outside the c-char-sequence, s-char-sequence, or r-char-sequence of a character or string literal corresponds to a control character (in either of the ranges 0x00-0x1F or 0x7F-0x9F, both inclusive) or to a character in the basic source character set, the program is ill-formed.

These restrictions should not apply to comment text. Arguably the prohibitions of control characters and characters in the basic character set already do not apply, as they require that the preprocessing tokens for literals have already been recognized; this occurs in phase 3, which also replaces comments with single spaces. However, the prohibition of surrogate code points is not so limited and might conceivably be applied within comments.

Probably the most straightforward way of addressing this problem would be simply to state in 2.8 [lex.comment] that character sequences that resemble universal-character-names are not recognized as such within comment text.

#### 411. Use of universal-character-name in character versus string literals

Section: 2.14.5 [lex.string] Status: open Submitter: James Kanze Date: 23 Apr 2003

2.14.5 [lex.string] paragraph 5 reads

> Escape sequences and universal-character-names in string literals have the same meaning as in character literals, except that the single quote ' is representable either by itself or by the escape sequence \', and the double quote " shall be preceded by a \. In a narrow string literal, a universal-character-name may map to more than one char element due to multibyte encoding.

The first sentence refers us to 2.14.3 [lex.ccon], where we read in the first paragraph that "An ordinary character literal that contains a single c-char has type char [...]." Since the grammar shows that a universal-character-name is a c-char, something like '\u1234' must have type char (and thus be a single char element); in paragraph 5, we read that "A universal-character-name is translated to the encoding, in the execution character set, of the character named. If there is no such encoding, the universal-character-name is translated to an implemenation-defined encoding."

This is in obvious contradiction with the second sentence. In addition, I'm not really clear what is supposed to happen in the case where the execution (narrow-)character set is UTF-8. Consider the character \u0153 (the oe in the French word oeuvre). Should '\u0153' be a char, with an "error" value, say '?' (in conformance with the requirement that it be a single char), or an int, with the two char values 0xC5, 0x93, in an implementation defined order (in conformance with the requirement that a character representable in the execution character set be represented). Supposing the former, should "\u0153" be the equivalent of "?" (in conformance with the first sentence), or "\xC5\x93" (in conformance with the second).

Notes from October 2003 meeting:

We decided we should forward this to the C committee and let them resolve it. Sent via e-mail to John Benito on November 14, 2003.

Reply from John Benito:

> I talked this over with the C project editor, we believe this was handled by the C committee before publication of the current standard.

> WG14 decided there needed to be a more restrictive rule for one-to-one mappings: rather than saying "a single c-char" as C++ does, the C standard says "a single character that maps to a single-byte execution character"; WG14 fully expect some (if not many or even most) UCNs to map to multiple characters.

> Because of the fundamental differences between C and C++ character types, I am not sure the C committee is qualified to answer this satisfactorily for WG21. WG14 is willing to review any decision reached for compatibility.

> I hope this helps.

(See also issue 912 for a related question.)

#### 1266. user-defined-integer-literal overflow

Section: 2.14.8 [lex.ext] Status: open Submitter: Michael Wong Date: 2011-03-20

The decimal-literal in a user-defined-integer-literal might be too large for an `unsigned long long` to represent (in implementations with extended integer types). In such cases, the original intent appears to have been to call a raw literal operator or a literal operator template; however, the existing wording of 2.14.8 [lex.ext] paragraph 3 always calls the `unsigned long long` literal operator if it exists, regardless of the value of the decimal-literal.

#### 1209. Is a potentially-evaluated expression in a template definition a “use?”

Section: 3.2 [basic.def.odr] Status: open Submitter: Johannes Schaub Date: 2010-10-08

Consider the following complete program:

        void f();
        template<typename T> void g() { f(); }
        int main() { }

Must `f()` be defined to make this program well-formed? The current wording of 3.2 [basic.def.odr] does not make any special provision for expressions that appear only in uninstantiated template definitions.

(See also issue 1254.)

#### 191. Name lookup does not handle complex nesting

Section: 3.4.1 [basic.lookup.unqual] Status: open Submitter: Alan Nash Date: 29 Dec 1999

The current description of unqualified name lookup in 3.4.1 [basic.lookup.unqual] paragraph 8 does not correctly handle complex cases of nesting. The Standard currently reads,

> A name used in the definition of a function that is a member function (9.3) of a class `X` shall be declared in one of the following ways:
> - before its use in the block in which it is used or in an enclosing block (6.3), or
> - shall be a member of class `X` or be a member of a base class of `X` (10.2), or
> - if `X` is a nested class of class `Y` (9.7), shall be a member of `Y`, or shall be a member of a base class of `Y` (this lookup applies in turn to `Y`'s enclosing classes, starting with the innermost enclosing class), or
> - if `X` is a local class (9.8) or is a nested class of a local class, before the definition of class `X` in a block enclosing the definition of class `X`, or
> - if `X` is a member of namespace `N`, or is a nested class of a class that is a member of `N`, or is a local class or nested class within a local class of a function that is a member of `N`, before the member function definition, in namespace `N` or in one of `N`'s enclosing namespaces.

In particular, this formulation does not handle the following example:

        struct outer {
            static int i;
            struct inner {
                void f() {
                    struct local {
                        void g() {
                            i = 5;
                        }
                    };
                }
            };
        };

Here the reference to `i` is from a member function of a local class of a member function of a nested class. Nothing in the rules allows `outer::i` to be found, although intuitively it should be found.

A more comprehensive formulation is needed that allows traversal of any combination of blocks, local classes, and nested classes. Similarly, the final bullet needs to be augmented so that a function need not be a (direct) member of a namespace to allow searching that namespace when the reference is from a member function of a class local to that function. That is, the current rules do not allow the following example:

        int j;    // global namespace
        struct S {
            void f() {
                struct local2 {
                    void g() {
                        j = 5;
                    }
                };
            }
        };

#### 405. Unqualified function name lookup

Section: 3.4.1 [basic.lookup.unqual] Status: open Submitter: William M. Miller Date: 14 Apr 2003

There seems to be some confusion in the Standard regarding the relationship between 3.4.1 [basic.lookup.unqual] (Unqualified name lookup) and 3.4.2 [basic.lookup.argdep] (Argument-dependent lookup). For example, 3.4.1 [basic.lookup.unqual] paragraph 3 says,

> The lookup for an unqualified name used as the postfix-expression of a function call is described in 3.4.2 [basic.lookup.argdep].

In other words, nothing in 3.4.1 [basic.lookup.unqual] applies to function names; the entire lookup is described in 3.4.2 [basic.lookup.argdep].

3.4.2 [basic.lookup.argdep] does not appear to share this view of its responsibility. The closest it comes is in 3.4.2 [basic.lookup.argdep] paragraph 2a:

> ...the set of declarations found by the lookup of the function name is the union of the set of declarations found using ordinary unqualified lookup and the set of declarations found in the namespaces and classes associated with the argument types.

Presumably, "ordinary unqualified lookup" is a reference to the processing described in 3.4.1 [basic.lookup.unqual], but, as noted above, 3.4.1 [basic.lookup.unqual] explicitly precludes applying that processing to function names. The details of "ordinary unqualified lookup" of function names are not described anywhere.

The other clauses that reference 3.4.2 [basic.lookup.argdep], clauses 13 [over] and 14 [temp], are split over the question of the relationship between 3.4.1 [basic.lookup.unqual] and 3.4.2 [basic.lookup.argdep]. 13.3.1.1.1 [over.call.func] paragraph 3, for instance, says

> The name is looked up in the context of the function call following the normal rules for name lookup in function calls (3.4.2 [basic.lookup.argdep]).

I.e., this reference assumes that 3.4.2 [basic.lookup.argdep] is self-contained. The same is true of 13.3.1.2 [over.match.oper] paragraph 3, second bullet:

> The set of non-member candidates is the result of the unqualified lookup of operator@ in the context of the expression according to the usual rules for name lookup in unqualified function calls (3.4.2 [basic.lookup.argdep]), except that all member functions are ignored.

On the other hand, however, 14.6.4.2 [temp.dep.candidate] paragraph 1 explicitly assumes that 3.4.1 [basic.lookup.unqual] and 3.4.2 [basic.lookup.argdep] are both involved in function name lookup and do different things:

> For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1 [basic.lookup.unqual], 3.4.2 [basic.lookup.argdep]) except that:
> - For the part of the lookup using unqualified name lookup (3.4.1 [basic.lookup.unqual]), only function declarations with external linkage from the template definition context are found.
> - For the part of the lookup using associated namespaces (3.4.2 [basic.lookup.argdep]), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.

Suggested resolution:

Change 3.4.1 [basic.lookup.unqual] paragraph 1 from

> ...name lookup ends as soon as a declaration is found for the name.

to

> ...name lookup ends with the first scope containing one or more declarations of the name.

Change the first sentence of 3.4.1 [basic.lookup.unqual] paragraph 3 from

> The lookup for an unqualified name used as the postfix-expression of a function call is described in 3.4.2 [basic.lookup.argdep].

to

> An unqualified name used as the postfix-expression of a function call is looked up as described below. In addition, argument-dependent lookup (3.4.2 [basic.lookup.argdep]) is performed on this name to complete the resulting set of declarations.

#### 1200. Lookup rules for template parameters

Section: 3.4.1 [basic.lookup.unqual] Status: open Submitter: Johannes Schaub Date: 2010-09-18

Although 3.3.9 [basic.scope.temp] now describes the scope of a template parameter, the description of unqualified name lookup in 3.4.1 [basic.lookup.unqual] do not cover uses of template parameter names. The note in 3.4.1 [basic.lookup.unqual] paragraph 16 says,

> the rules for name lookup in template definitions are described in 14.6 [temp.res].

but the rules there cover dependent and non-dependent names, not template parameters themselves.

#### 562. qualified-ids in non-expression contexts

Section: 3.4.3.1 [class.qual] Status: open Submitter: Mike Miller Date: 6 April 2006

Both 3.4.3.1 [class.qual] and 3.4.3.2 [namespace.qual] specify that some lookups are to be performed “in the context of the entire postfix-expression,” ignoring the fact that qualified-ids can appear outside of expressions.

It was suggested in document J16/05-0156 = WG21 N1896 that these uses be changed to “the context in which the qualified-id occurs,” but it isn't clear that this formulation adequately covers all the places a qualified-id can occur.

#### 278. External linkage and nameless entities

Section: 3.5 [basic.link] Status: open Submitter: Daveed Vandevoorde Date: 12 Apr 2000

It is unclear to what extent entities without names match across translation units. For example,

        struct S {
           int :2;
           enum { a, b, c } x;
           static class {} *p;
        };

If this declaration appears in multiple translation units, are all these members "the same" in each declaration?

A similar question can be asked about non-member declarations:

        // Translation unit 1:
        extern enum { d, e, f } y;

        // Translation unit 2:
        extern enum { d, e, f } y;

        // Translation unit 3:
        enum { d, e, f } y;

Is this valid C++? Is it valid C?

James Kanze: `S::p` cannot be defined, because to do so requires a type specifier and the type cannot be named. `::y` is valid C because C only requires compatible, not identical, types. In C++, it appears that there is a new type in each declaration, so it would not be valid. This differs from `S::x` because the unnamed type is part of a named type — but I don't know where or if the Standard says that.

John Max Skaller: It's not valid C++, because the type is a synthesised, unique name for the enumeration type which differs across translation units, as if:

        extern enum _synth1 { d,e,f} y;
        ..
        extern enum _synth2 { d,e,f} y;

had been written.

However, within a class, the ODR implies the types are the same:

        class X { enum { d } y; };

in two translation units ensures that the type of member `y` is the same: the two `X`'s obey the ODR and so denote the same class, and it follows that there's only one member `y` and one type that it has.

(See also issues 132 and 216.)

#### 279. Correspondence of "names for linkage purposes"

Section: 3.5 [basic.link] Status: open Submitter: Daveed Vandevoorde Date: 4 Apr 2001

The standard says that an unnamed class or enum definition can be given a "name for linkage purposes" through a typedef. E.g.,

        typedef enum {} E;
        extern E *p;

can appear in multiple translation units.

How about the following combination?

        // Translation unit 1:
        struct S;
        extern S *q;

        // Translation unit 2:
        typedef struct {} S;
        extern S *q;

Is this valid C++?

Also, if the answer is "yes", consider the following slight variant:

        // Translation unit 1:
        struct S {};  // <<-- class has definition
        extern S *q;

        // Translation unit 2:
        typedef struct {} S;
        extern S *q;

Is this a violation of the ODR because two definitions of type `S` consist of differing token sequences?

#### 338. Enumerator name with linkage used as class name in other translation unit

Section: 3.5 [basic.link] Status: open Submitter: Daveed Vandevoorde Date: 26 Feb 2002

The following declarations are allowed within a translation unit:

      struct S;
      enum { S };

However, 3.5 [basic.link] paragraph 9 seems to say these two declarations cannot appear in two different translation units. That also would mean that the inclusion of a header containing the above in two different translation units is not valid C++.

I suspect this is an oversight and that users should be allowed to have the declarations above appear in different translation units. (It is a fairly common thing to do, I think.)

Mike Miller: I think you meant "`enum E { S };`" -- enumerators only have external linkage if the enumeration does (3.5 [basic.link] paragraph 4), and 3.5 [basic.link] paragraph 9 only applies to entities with external linkage.

I don't remember why enumerators were given linkage; I don't think it's necessary for mangling non-type template arguments. In any event, I can't think why cross-TU name collisions between enumerators and other entities would cause a problem, so I guess a change here would be okay. I can think of three changes that would have that effect:

1. Saying that enumerators do not have linkage.
2. Removing enumerators from the list of entities in the first sentence of 3.5 [basic.link] paragraph 9.
3. Saying that it's okay for an enumerator in one TU to have the same name as a class type in another TU only if the enumerator hides that same class type in both TUs (the example you gave).

Daveed Vandevoorde: I don't think any of these are sufficient in the sense that the problem isn't limited to enumerators. E.g.:

      struct X;
      extern void X();

shouldn't create cross-TU collisions either.

Mike Miller: So you're saying that cross-TU collisions should only be prohibited if both names denote entities of the same kind (both functions, both objects, both types, etc.), or if they are both references (regardless of what they refer to, presumably)?

Daveed Vandevoorde: Not exactly. Instead, I'm saying that if two entities (with external linkage) can coexist when they're both declared in the same translation unit (TU), then they should also be allowed to coexist when they're declared in two different translation units.

For example:

      int i;
      void i();  // Error

This is an error within a TU, so I don't see a reason to make it valid across TUs.

However, "tag names" (class/struct/union/enum) can sometimes coexist with identically named entities (variables, functions & enumerators, but not namespaces, templates or type names).

#### 371. Interleaving of constructor calls

Section: 3.6.2 [basic.start.init] Status: open Submitter: Matt Austern Date: 7 August 2002

Is a compiler allowed to interleave constructor calls when performing dynamic initialization of nonlocal objects? What I mean by interleaving is: beginning to execute a particular constructor, then going off and doing something else, then going back to the original constructor. I can't find anything explicit about this in clause 3.6.2 [basic.start.init].

I'll present a few different examples, some of which get a bit wild. But a lot of what this comes down to is exactly what the standard means when it talks about the order of initialization. If it says that some object x must be initialized before a particular event takes place, does that mean that x's constructor must be entered before that event, or does it mean that it must be exited before that event? If object x must be initialized before object y, does that mean that x's constructor must exit before y's constructor is entered?

(The answer to that question might just be common sense, but I couldn't find an answer in clause 3.6.2 [basic.start.init]. Actually, when I read 3.6.2 [basic.start.init] carefully, I find there are a lot of things I took for granted that aren't there.)

OK, so a few specific scenerios.

1. We have a translation unit with nonlocal objects A and B, both of which require dynamic initialization. A comes before B. A must be initialized before B. May the compiler start to construct A, get partway through the constructor, then construct B, and then go back to finishing A?
2. We have a translation unit with nonlocal object A and function f. Construction of A is deferred until after the first statement of main. A must be constructed before the first use of f. Is the compiler permitted to start constructing A, then execute f, then go back to constructing A?
3. We have nonlocal objects A and B, in two different translation units. The order in which A and B are constructed is unspecified by the Standard. Is the compiler permitted to begin constructing A, then construct B, then finish A's constructor? Note the implications of a 'yes' answer. If A's and B's constructor both call some function f, then the call stack might look like this:

          <runtime gunk>
            <Enter A's constructor>
               <Enter f>
                  <runtime gunk>
                     <Enter B's constructor>
                        <Enter f>
                        <Leave f>
                     <Leave B's constructor>
               <Leave f>
            <Leave A's constructor>

   The implication of a 'yes' answer for users is that any function called by a constructor, directly or indirectly, must be reentrant.
4. This last example is to show why a 'no' answer to #3 might be a problem too. New scenerio: we've got one translation unit containing a nonlocal object A and a function f1, and another translation unit containing a nonlocal object B and a function f2. A's constructor calls f2. Initialization of A and B is deferred until after the first statement of main(). Someone in main calls f1. Question: is the compiler permitted to start constructing A, then go off and construct B at some point before f2 gets called, then go back and finish constructing A? In fact, is the compiler required to do that? We've got an unpleasant tension here between the bad implications of a 'yes' answer to #3, and the explicit requirement in 3.6.2 [basic.start.init] paragraph 3.

At this point, you might be thinking we could avoid all of this nonsense by removing compilers' freedom to defer initialization until after the beginning of main(). I'd resist that, for two reasons. First, it would be a huge change to make after the standard has been out. Second, that freedom is necessary if we want to have support for dynamic libraries. I realize we don't yet say anything about dynamic libraries, but I'd hate to make decisions that would make such support even harder.

#### 640. Accessing destroyed local objects of static storage duration

Section: 3.6.3 [basic.start.term] Status: open Submitter: Howard Hinnant Date: 30 July 2007

3.6.3 [basic.start.term] paragraph 2 says,

> If a function contains a local object of static storage duration that has been destroyed and the function is called during the destruction of an object with static storage duration, the program has undefined behavior if the flow of control passes through the definition of the previously destroyed local object.

I would like to turn this behavior from undefined to well-defined behavior for the purpose of achieving a graceful shutdown, especially in a multi-threaded world.

Background: Alexandrescu describes the “phoenix singleton” in Modern C++ Design. This is a class used as a function local static, that will reconstruct itself, and reapply itself to the `atexit` chain, if the program attempts to use it after it is destructed in the `atexit` chain. It achieves this by setting a “destructed flag” in its own state in its destructor. If the object is later accessed (and a member function is called on it), the member function notes the state of the “destructed flag” and does the reconstruction dance. The phoenix singleton pattern was designed to address issues only in single-threaded code where accesses among static objects can have a non-scoped pattern. When we throw in multi-threading, and the possibility that threads can be running after `main` returns, the chances of accessing a destroyed static significantly increase.

The very least that I would like to see happen is to standardize what I believe is existing practice: When an object is destroyed in the `atexit` chain, the memory the object occupied is left in whatever state the destructor put it in. If this can only be reliably done for objects with standard layout, that would be an acceptable compromise. This would allow objects to set “I'm destructed” flags in their state and then do something well-defined if accessed, such as throw an exception.

A possible refinement of this idea is to have the compiler set up a 3-state flag around function-local statics instead of the current 2-state flag:

- Not constructed yet
- Constructed but not destroyed yet
- Destroyed

We have the first two states today. We might choose to add the third state, and if execution passes over a function-local static with “destroyed” state, an exception could be thrown. This would mean that we would not have to guarantee memory stability in destroyed objects of static duration.

This refinement would break phoenix singletons, and is not required for the `~mutex()`/`~condition()` I've described and prototyped. But it might make it easier for Joe Coder to apply this kind of guarantee to his own types.

#### 365. Storage duration and temporaries

Section: 3.7 [basic.stc] Status: open Submitter: James Kanze Date: 24 July 2002

There are several problems with 3.7 [basic.stc]:

- 3.7 [basic.stc] paragraph 2 says that "Static and automatic storage durations are associated with objects introduced by declarations (3.1 [basic.def]) and implicitly created by the implementation (12.2 [class.temporary])."

  In fact, objects "implicitly created by the implementation" are the temporaries described in (12.2 [class.temporary]), and have neither static nor automatic storage duration, but a totally different duration, described in 12.2 [class.temporary].

- 3.7 [basic.stc] uses the expression "local object" in several places, without ever defining it. Presumably, what is meant is "an object declared at block scope", but this should be said explicitly.

  In a recent discussion in comp.lang.c++.moderated, on poster interpreted "local objects" as including temporaries. This would require them to live until the end of the block in which they are created, which contradicts 12.2 [class.temporary]. If temporaries are covered by this section, and the statement in 3.7 [basic.stc] seems to suggest, and they aren't local objects, then they must have static storage duration, which isn't right either.

  I propose adding a fourth storage duration to the list after 3.7 [basic.stc] paragraph 1:

  - temporary storage duration

  And rewriting the second paragraph of this section as follows:

  > Temporary storage duration is associated with objects implicitly created by the implementation, and is described in 12.2 [class.temporary]. Static and automatic storage durations are associated with objects defined by declarations; in the following, an object defined by a declaration with block scope is a local object. The dynamic storage duration is associated with objects created by the `operator new`.

Steve Adamczyk: There may well be an issue here, but one should bear in mind the difference between storage duration and object lifetime. As far as I can see, there is no particular problem with temporaries having automatic or static storage duration, as appropriate. The point of 12.2 [class.temporary] is that they have an unusual object lifetime.

Notes from Ocrober 2002 meeting:

It might be desirable to shorten the storage duration of temporaries to allow reuse of them. The as-if rule allows some reuse, but such reuse requires analysis, including noting whether the addresses of such temporaries have been taken.

Notes from the August, 2011 meeting:

The CWG decided that further consideration of this issue would be deferred until someone produces a paper explaining the need for action and proposing specific changes.

#### 967. Exception specification of replacement allocation function

Section: 3.7.4 [basic.stc.dynamic] Status: open Submitter: Steve Clamage Date: 15 September, 2009

The global allocation functions are implicitly declared in every translation unit with exception-specifications (3.7.4 [basic.stc.dynamic] paragraph 2). It is not clear what should happen if a replacement allocation function is declared without an exception-specification. Is that a conflict with the implicitly-declared function (as it would be with explicitly-declared functions, and presumably is if the `<new>` header is included)? Or does the new declaration replace the implicit one, including the lack of an exception-specification? Or does the implicit declaration prevail? (Regardless of the exception-specification or lack thereof, it is presumably undefined behavior for an allocation function to exit with an exception that cannot be caught by a handler of type `std::bad_alloc` (3.7.4.1 [basic.stc.dynamic.allocation] paragraph 3).)

#### 1338. Aliasing and allocation functions

Section: 3.7.4.1 [basic.stc.dynamic.allocation] Status: open Submitter: Jason Merrill Date: 2011-08-03

In 3.7.4.1 [basic.stc.dynamic.allocation] paragraph 3, allocation functions are constrained to return a pointer that is different from any previously returned pointer that has not been passed to a deallocation function. This does not, for instance, prohibit returning a pointer to storage that is part of another object, for example, a pool of storage. The potential implications of this for aliasing should be spelled out.

(See also issues 1027 and 1116.)

#### 523. Can a one-past-the-end pointer be invalidated by deleting an adjacent object?

Section: 3.7.4.2 [basic.stc.dynamic.deallocation] Status: open Submitter: comp.std.c++ Date: 8 July 2005

When an object is deleted, 3.7.4.2 [basic.stc.dynamic.deallocation] says that the deallocation “[renders] invalid all pointers referring to any part of the deallocated storage.” According to 3.9.2 [basic.compound] paragraph 3, a pointer whose address is one past the end of an array is considered to point to an unrelated object that happens to reside at that address. Does this need to be clarified to specify that the one-past-the-end pointer of an array is not invalidated by deleting the following object? (See also 5.3.5 [expr.delete] paragraph 4, which also mentions that the system deallocation function renders a pointer invalid.)

#### 419. Can cast to virtual base class be done on partially-constructed object?

Section: 3.8 [basic.life] Status: open Submitter: Judy Ward Date: 2 June 2003

Consider

      extern "C" int printf (const char *,...);

      struct Base { Base();};
      struct Derived: virtual public Base {
         Derived() {;}
      };

      Derived d;
      extern Derived& obj = d;

      int i;

      Base::Base() {
        if ((Base *) &obj) i = 4;
        printf ("i=%d\n", i);
      }

      int main() { return 0; }

12.7 [class.cdtor] paragraph 2 makes this valid, but 3.8 [basic.life] paragraph 5 implies that it isn't valid.

Steve Adamczyk: A second issue:

      extern "C" int printf(const char *,...);
      struct A                      { virtual ~A(); int x; };
      struct B : public virtual A   { };
      struct C : public B           { C(int); };
      struct D : public C           { D(); };

      int main()                    { D t; printf("passed\n");return 0; }

      A::~A()                       {}
      C::C(int)                     {}
      D::D() : C(this->x)           {}

Core issue 52 almost, but not quite, says that in evaluating "this->x" you do a cast to the virtual base class A, which would be an error according to 12.7 [class.cdtor] paragraph 2 because the base class B constructor hasn't started yet. 5.2.5 [expr.ref] should be clarified to say that the cast does need to get done.

James Kanze submitted the same issue via comp.std.c++ on 11 July 2003:

> Richard Smith: Nonsense. You can use "this" perfectly happily in a constructor, just be careful that (a) you're not using any members that are not fully initialised, and (b) if you're calling virtual functions you know exactly what you're doing.

In practice, and I think in intent, you are right. However, the standard makes some pretty stringent restrictions in 3.8 [basic.life]. To start with, it says (in paragraph 1):

> The lifetime of an object is a runtime property of the object. The lifetime of an object of type T begins when:
> - storage with the proper alignment and size for type T is obtained, and
> - if T is a class type with a non-trivial constructor, the constructor calls has COMPLETED.
> The lifetime of an object of type T ends when:
> - if T is a class type with a non-trivial destructor, the destructor call STARTS, or
> - the storage which the object occupies is reused or released.

(Emphasis added.) Then when we get down to paragraph 5, it says:

> Before the lifetime of an object has started but after the storage which the object will occupy has been allocated [which sounds to me like it would include in the constructor, given the text above] or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. [...] If the object will be or was of a non-POD class type, the program has undefined behavior if:

> [...]

> - the pointer is implicitly converted to a pointer to a base class type, or [...]

I can't find any exceptions for the this pointer.

Note that calling a non-static function in the base class, or even constructing the base class in initializer list, involves an implicit conversion of this to a pointer to the base class. Thus undefined behavior. I'm sure that this wasn't the intent, but it would seem to be what this paragraph is saying.

#### 1285. Trivial destructors and object lifetime

Section: 3.8 [basic.life] Status: open Submitter: Johannes Schaub Date: 2011-04-02

The Standard is self-contradictory regarding which destructor calls end the lifetime of an object. 3.8 [basic.life] paragraph 1 says,

> The lifetime of an object of type T ends when:

> - if `T` is a class type with a non-trivial destructor (12.4 [class.dtor]), the destructor call starts, or

> - the storage which the object occupies is reused or released.

i.e., the lifetime of an object of a class type with a trivial destructor persists until its storage is reused or released. However, 12.4 [class.dtor] paragraph 15 says,

> Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8 [basic.life]).

implying that invoking any destructor, even a trivial one, ends the lifetime of the associated object. Similarly, 12.7 [class.cdtor] paragraph 1 says,

> For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.

A similar question arises for pseudo-destructors for non-class types.

Notes from the August, 2011 meeting:

CWG will need a paper exploring this topic before it can act on the issue.

#### 350. `signed char` underlying representation for objects

Section: 3.9 [basic.types] Status: open Submitter: Noah Stein Date: 16 April 2002

Sent in by David Abrahams:

Yes, and to add to this tangent, 3.9.1 [basic.fundamental] paragraph 1 states "Plain char, signed char, and unsigned char are three distinct types." Strangely, 3.9 [basic.types] paragraph 2 talks about how "... the underlying bytes making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value." I guess there's no requirement that this copying work properly with signed chars!

Notes from October 2002 meeting:

We should do whatever C99 does. 6.5p6 of the C99 standard says "array of character type", and "character type" includes signed char (6.2.5p15), and 6.5p7 says "character type". But see also 6.2.6.1p4, which mentions (only) an array of unsigned char.

Proposed resolution (April 2003):

Change 3.8 [basic.life] paragraph 5 bullet 3 from

- the pointer is used as the operand of a `static_cast` (5.2.9 [expr.static.cast]) (except when the conversion is to `void*`, or to `void*` and subsequently to `char*`, or `unsigned` `char*`).

to

- the pointer is used as the operand of a `static_cast` (5.2.9 [expr.static.cast]) (except when the conversion is to `void*`, or to `void*` and subsequently to a pointer to byte-character type).

Change 3.8 [basic.life] paragraph 6 bullet 3 from

- the lvalue is used as the operand of a `static_cast` (5.2.9 [expr.static.cast]) (except when the conversion is ultimately to `char&` or `unsigned` `char&`), or

to

- the lvalue is used as the operand of a `static_cast` (5.2.9 [expr.static.cast]) (except when the conversion is ultimately to a reference to byte-character type), or

Change the beginning of 3.9 [basic.types] paragraph 2 from

> For any object (other than a base-class subobject) of POD type `T`, whether or not the object holds a valid value of type `T`, the underlying bytes (1.7 [intro.memory]) making up the object can be copied into an array of `char` or `unsigned` `char`.

to

> For any object (other than a base-class subobject) of POD type `T`, whether or not the object holds a valid value of type `T`, the underlying bytes (1.7 [intro.memory]) making up the object can be copied into an array of byte-character type.

Add the indicated text to 3.9.1 [basic.fundamental] paragraph 1:

> Objects declared as characters (`char`) shall be large enough to store any member of the implementation's basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation-defined whether a `char` object can hold negative values. Characters can be explicitly declared `unsigned` or `signed`. Plain `char`, `signed char`, and `unsigned char` are three distinct types, called the byte-character types. A `char`, a `signed char`, and an `unsigned char` occupy the same amount of storage and have the same alignment requirements (3.9 [basic.types]); that is, they have the same object representation. For byte-character types, all bits of the object representation participate in the value representation. For unsigned byte-character types, all possible bit patterns of the value representation represent numbers. These requirements do not hold for other types. In any particular implementation, a plain `char` object can take on either the same values as a `signed char` or an `unsigned char`; which one is implementation-defined.

Change 3.10 [basic.lval] paragraph 15 last bullet from

- a `char` or `unsigned` `char` type.

to

- a byte-character type.

Notes from October 2003 meeting:

It appears that in C99 signed char may have padding bits but no trap representation, whereas in C++ signed char has no padding bits but may have -0. A memcpy in C++ would have to copy the array preserving the actual representation and not just the value.

March 2004: The liaisons to the C committee have been asked to tell us whether this change would introduce any unnecessary incompatibilities with C.

Notes from October 2004 meeting:

The C99 Standard appears to be inconsistent in its requirements. For example, 6.2.6.1 paragraph 4 says:

> The value may be copied into an object of type `unsigned char [`n`]` (e.g., by `memcpy`); the resulting set of bytes is called the object representation of the value.

On the other hand, 6.2 paragraph 6 says,

> If a value is copied into an object having no declared type using `memcpy` or `memmove`, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one.

Mike Miller will investigate further.

Proposed resolution (February, 2010):

1. Change 3.8 [basic.life] paragraph 5 bullet 4 as follows:

> ...The program has undefined behavior if:

> - ...

> - the pointer is used as the operand of a `static_cast` (5.2.9 [expr.static.cast]) (except when the conversion is to cv `void*`, or to cv `void*` and subsequently to `char*`, or `unsigned char*` a pointer to a cv-qualified or cv-unqualified byte-character type (3.9.1 [basic.fundamental])), or

> - ...

2. Change 3.8 [basic.life] paragraph 6 bullet 4 as follows:

> ...The program has undefined behavior if:

> - ...

> - the lvalue is used as the operand of a `static_cast` (5.2.9 [expr.static.cast]) except when the conversion is ultimately to cv `char&` or cv `unsigned char&` a reference to a cv-qualified or cv-unqualified byte-character type (3.9.1 [basic.fundamental]) or an array thereof, or

> - ...

3. Change 3.9 [basic.types] paragraph 2 as follows:

> For any object (other than a base-class subobject) of trivially copyable type `T`, whether or not the object holds a valid value of type `T`, the underlying bytes (1.7 [intro.memory]) making up the object can be copied into an array of `char` or `unsigned char` a byte-character type (3.9.1 [basic.fundamental]).39 If the content of the that array of `char` or `unsigned char` is copied back into the object, the object shall subsequently hold its original value. [Example:...

4. Change 3.9.1 [basic.fundamental] paragraph 1 as follows:

> ...Characters can be explicitly declared `unsigned` or `signed`. Plain `char`, `signed char`, and `unsigned char` are three distinct types, called the byte-character types. A `char`, a `signed char`, and an `unsigned char` occupy the same amount of storage and have the same alignment requirements (3.11 [basic.align]); that is, they have the same object representation. For byte-character types, all bits of the object representation participate in the value representation. For unsigned character types `unsigned char`, all possible bit patterns of the value representation represent numbers...

5. Change 3.10 [basic.lval] paragraph 15 final bullet as follows:

> If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined 52

> - ...

> - a `char` or `unsigned char` byte-character type (3.9.1 [basic.fundamental]).

6. Change 3.11 [basic.align] paragraph 6 as follows:

> The alignment requirement of a complete type can be queried using an `alignof` expression (5.3.6 [expr.alignof]). Furthermore, the byte-character types (3.9.1 [basic.fundamental]) `char`, `signed char`, and `unsigned char` shall have the weakest alignment requirement. [Note: this enables the byte-character types to be used as the underlying type for an aligned memory area (7.6.2 [dcl.align]). —end note]

7. Change 5.3.4 [expr.new] paragraph 10 as follows:

> ...For arrays of `char` and `unsigned char` a byte-character type (3.9.1 [basic.fundamental]), the difference between the result of the new-expression and the address returned by the allocation function shall be an integral multiple of the strictest fundamental alignment requirement (3.11 [basic.align]) of any object type whose size is no greater than the size of the array being created. [Note: Because allocation functions are assumed to return pointers to storage that is appropriately aligned for objects of any type with fundamental alignment, this constraint on array allocation overhead permits the common idiom of allocating byte-character arrays into which objects of other types will later be placed. —end note]

Notes from the March, 2010 meeting:

The CWG was not convinced that there was a need to change the existing specification at this time. Some were concerned that there might be implementation difficulties with giving `signed char` the requisite semantics; implementations for which that is true can currently make `char` equivalent to `unsigned char` and avoid those problems, but the suggested change would undermine that strategy.

#### 146. Floating-point zero

Section: 3.9.1 [basic.fundamental] Status: open Submitter: Andy Sawyer Date: 23 Jul 1999

3.9.1 [basic.fundamental] does not impose a requirement on the floating point types that there be an exact representation of the value zero. This omission is significant in 4.12 [conv.bool] paragraph 1, in which any non-zero value converts to the `bool` value `true`.

Suggested resolution: require that all floating point types have an exact representation of the value zero.

#### 251. How many signed integer types are there?

Section: 3.9.1 [basic.fundamental] Status: open Submitter: Beman Dawes Date: 18 Oct 2000

3.9.1 [basic.fundamental] paragraph 2 says that

> There are four signed integer types: "`signed char`", "`short int`", "`int`", and "`long int`."

This would indicate that `const int` is not a signed integer type.

#### 689. Maximum values of signed and unsigned integers

Section: 3.9.1 [basic.fundamental] Status: open Submitter: James Kanze Date: 30 March, 2008

The relationship between the values representable by corresponding signed and unsigned integer types is not completely described, but 3.9 [basic.types] paragraph 4 says,

> The value representation of an object is the set of bits that hold the value of type `T`.

and 3.9.1 [basic.fundamental] paragraph 3 says,

> The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the value representation of each corresponding signed/unsigned type shall be the same.

I.e., the maximum value of each unsigned type must be larger than the maximum value of the corresponding signed type.

C90 doesn't have this restriction, and C99 explicitly says (6.2.6.2, paragraph 2),

> For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; there shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M <= N).

Unlike C++, the sign bit is not part of the value, and on an architecture that does not have native support of unsigned types, an implementation can emulate unsigned integers by simply ignoring what would be the sign bit in the signed type and be conforming.

The question is whether we intend to make a conforming implementation on such an architecture impossible. More generally, what range of architectures do we intend to support? And to what degree do we want to follow C99 in its evolution since C89?

(See paper J16/08-0141 = WG21 N2631.)

#### 1076. Value categories and lvalue temporaries

Section: 3.10 [basic.lval] Status: open Submitter: Daniel Krügler Date: 2010-06-10

The taxonomy of value categories in 3.10 [basic.lval] classifies temporaries as prvalues. However, some temporaries are explicitly referred to as lvalues (cf 15.1 [except.throw] paragraph 3).

#### 330. Qualification conversions and pointers to arrays of pointers

Section: 4.4 [conv.qual] Status: open Submitter: Roger Orr Date: 2 Jan 2002

Section 4.4 [conv.qual] covers the case of multi-level pointers, but does not appear to cover the case of pointers to arrays of pointers. The effect is that arrays are treated differently from simple scalar values.

Consider for example the following code: (from the thread "Pointer to array conversion question" begun in comp.lang.c++.moderated)

      int main()
      {
         double *array2D[2][3];

         double       *       (*array2DPtr1)[3] = array2D;     // Legal
         double       * const (*array2DPtr2)[3] = array2DPtr1; // Legal
         double const * const (*array2DPtr3)[3] = array2DPtr2; // Illegal
      }

and compare this code with:-

      int main()
      {
         double *array[2];

         double       *       *ppd1 = array; // legal
         double       * const *ppd2 = ppd1;  // legal
         double const * const *ppd3 = ppd2;  // certainly legal (4.4/4)
      }

The problem appears to be that the pointed to types in example 1 are unrelated since nothing in the relevant section of the standard covers it - 4.4 [conv.qual] does not mention conversions of the form "cv array of N pointer to T" into "cv array of N pointer to cv T"

It appears that reinterpret_cast is the only way to perform the conversion.

Suggested resolution:

Artem Livshits proposed a resolution :-

"I suppose if the definition of "similar" pointer types in 4.4 [conv.qual] paragraph 4 was rewritten like this:

> T1 is cv1,0 P0 cv1,1 P1 ... cv1,n-1 Pn-1 cv1,n T

> and

> T2 is cv1,0 P0 cv1,1 P1 ... cv1,n-1 Pn-1 cv1,n T

> where Pi is either a "pointer to" or a "pointer to an array of Ni"; besides P0 may be also a "reference to" or a "reference to an array of N0" (in the case of P0 of T2 being a reference, P0 of T1 may be nothing).

it would address the problem.

In fact I guess Pi in this notation may be also a "pointer to member", so 4.4 [conv.qual]/{4,5,6,7} would be nicely wrapped in one paragraph."

#### 238. Precision and accuracy constraints on floating point

Section: 5 [expr] Status: open Submitter: Christophe de Dinechin Date: 31 Jul 2000

It is not clear what constraints are placed on a floating point implementation by the wording of the Standard. For instance, is an implementation permitted to generate a "fused multiply-add" instruction if the result would be different from what would be obtained by performing the operations separately? To what extent does the "as-if" rule allow the kinds of optimizations (e.g., loop unrolling) performed by FORTRAN compilers?

#### 943. Is `T()` a temporary?

Section: 5.2.3 [expr.type.conv] Status: open Submitter: Miller Date: 14 July, 2009

According to 5.2.3 [expr.type.conv] paragraphs 1 and 3 (stated directly or by reference to another section of the Standard), all the following expressions create temporaries:

        T(1)
        T(1, 2)
        T{1}
        T{}

However, paragraph 2 says,

> The expression `T()`, where `T` is a simple-type-specifier or typename-specifier for a non-array complete effective object type or the (possibly cv-qualified) `void` type, creates an rvalue of the specified type, which is value-initialized (8.5 [dcl.init]; no initialization is done for the `void()` case).

This does not say that the result is a temporary, which means that the lifetime of the result is not specified by 12.2 [class.temporary]. Presumably this is just an oversight.

Notes from the October, 2009 meeting:

The specification in 5.2.3 [expr.type.conv] is in error, not because it fails to state that `T()` is a temporary but because it requires a temporary for the other cases with fewer than two operands. The case where `T` is a class type is covered by 12.2 [class.temporary] paragraph 1 (“a conversion that creates an rvalue”), and a temporary should not be created when `T` is not a class type.

#### 742. Postfix increment/decrement with long bit-field operands

Section: 5.2.6 [expr.post.incr] Status: open Submitter: Mike Miller Date: 11 November, 2008

Given the following declarations:

        struct S {
            signed long long sll: 3;
        };
        S s = { -1 };

the expressions `s.sll-- < 0u` and `s.sll < 0u` have different results. The reason for this is that `s.sll--` is an rvalue of type `signed long long` (5.2.6 [expr.post.incr]), which means that the usual arithmetic conversions (5 [expr] paragraph 10) convert `0u` to `signed long long` and the result is `true`. `s.sll`, on the other hand, is a bit-field lvalue, which is promoted (4.5 [conv.prom] paragraph 3) to `int`; both operands of `<` have the same rank, so `s.sll` is converted to `unsigned int` to match the type of `0u` and the result is `false`. This disparity seems undesirable.

#### 282. Namespace for `extended_type_info`

Section: 5.2.8 [expr.typeid] Status: open Submitter: Jens Maurer Date: 01 May 2001

The original proposed resolution for issue 160 included changing `extended_type_info` (5.2.8 [expr.typeid] paragraph 1, footnote 61) to `std::extended_type_info`. There was no consensus on whether this name ought to be part of namespace `std` or in a vendor-specific namespace, so the question was moved into a separate issue.

#### 528. Why are incomplete class types not allowed with `typeid`?

Section: 5.2.8 [expr.typeid] Status: open Submitter: Dave Abrahams Date: 18 May 2005

5.2.8 [expr.typeid] paragraph 4 says,

> When `typeid` is applied to a type-id, the result refers to a `std::type_info` object representing the type of the type-id. If the type of the type-id is a reference type, the result of the `typeid` expression refers to a `std::type_info` object representing the referenced type. If the type of the type-id is a class type or a reference to a class type, the class shall be completely-defined.

I'm wondering whether this is not overly restrictive. I can't think of a reason to require that `T` be completely-defined in `typeid(T)` when `T` is a class type. In fact, several popular compilers enforce that restriction for `typeid(T)`, but not for `typeid(T&)`. Can anyone explain this?

Nathan Sidwell: I think this restriction is so that whenever the compiler has to emit a typeid object of a class type, it knows what the base classes are, and can therefore emit an array of pointers-to-base-class typeids. Such a tree is necessary to implement `dynamic_cast` and exception catching (in a commonly implemented and obvious manner). If the class could be incomplete, the compiler might have to emit a typeid for incomplete `Foo` in one object file and a typeid for complete `Foo` in another object file. The compilation system will then have to make sure that (a) those compare equal and (b) the complete `Foo` gets priority, if that is applicable.

Unfortunately, there is a problem with exceptions that means there still can be a need to emit typeids for incomplete class. Namely one can throw a pointer-to-pointer-to-incomplete. To implement the matching of pointer-to-derived being caught by pointer-to-base, it is necessary for the typeid of a pointer type to contain a pointer to the typeid of the pointed-to type. In order to do the qualification matching on a multi-level pointer type, one has a chain of pointer typeids that can terminate in the typeid of an incomplete type. You cannot simply NULL-terminate the chain, because one must distinguish between different incomplete types.

Dave Abrahams: So if implementations are still required to be able to do it, for all practical purposes, why aren't we letting the user have the benefits?

Notes from the April, 2006 meeting:

There was some concern expressed that this might be difficult under the IA64 ABI. It was also observed that while it is necessary to handle exceptions involving incomplete types, there is no requirement that the RTTI data structures be used for exception handling.

#### 944. `reinterpret_cast` for all types with the same size and alignment

Section: 5.2.10 [expr.reinterpret.cast] Status: open Submitter: Miller Date: 15 July, 2009

During the discussion of issue 799, which specified the result of using `reinterpret_cast` to convert an operand to its own type, it was observed that it is probably reasonable to allow `reinterpret_cast` between any two types that have the same size and alignment.

#### 1230. Confusing description of ambiguity of destructor name

Section: 5.3.1 [expr.unary.op] Status: open Submitter: Johannes Schaub Date: 2010-12-13

According to 5.3.1 [expr.unary.op] paragraph 10,

> There is an ambiguity in the unary-expression `~X()`, where `X` is a class-name or decltype-specifier. The ambiguity is resolved in favor of treating `~` as a unary complement rather than treating `~X` as referring to a destructor.

It is not clear whether this is intended to apply to an expression like `(~S)()`. In large measure, that depends on whether a class-name is an id-expression or not. If it is, the ambiguity described in 5.3.1 [expr.unary.op] paragraph 10 does apply; if not, the expression is an unambiguous reference to the destructor for class `S`. There are several places in the Standard that indicate that the name of a type is an id-expression, but that might be more confusing than helpful.

#### 267. Alignment requirement for new-expressions

Section: 5.3.4 [expr.new] Status: open Submitter: James Kuyper Date: 4 Dec 2000

Requirements for the alignment of pointers returned by new-expressions are given in 5.3.4 [expr.new] paragraph 10:

> For arrays of `char` and `unsigned char`, the difference between the result of the new-expression and the address returned by the allocation function shall be an integral multiple of the most stringent alignment requirement (3.9 [basic.types]) of any object type whose size is no greater than the size of the array being created.

The intent of this wording is that the pointer returned by the new-expression will be suitably aligned for any data type that might be placed into the allocated storage (since the allocation function is constrained to return a pointer to maximally-aligned storage). However, there is an implicit assumption that each alignment requirement is an integral multiple of all smaller alignment requirements. While this is probably a valid assumption for all real architectures, there's no reason that the Standard should require it.

For example, assume that `int` has an alignment requirement of 3 bytes and `double` has an alignment requirement of 4 bytes. The current wording only requires that a buffer that is big enough for an `int` or a `double` be aligned on a 4-byte boundary (the more stringent requirement), but that would allow the buffer to be allocated on an 8-byte boundary — which might not be an acceptable location for an `int`.

Suggested resolution: Change "of any object type" to "of every object type."

A similar assumption can be found in 5.2.10 [expr.reinterpret.cast] paragraph 7:

> ...converting an rvalue of type "pointer to `T1`" to the type "pointer to `T2`" (where ... the alignment requirements of `T2` are no stricter than those of `T1`) and back to its original type yields the original pointer value...

Suggested resolution: Change the wording to

> ...converting an rvalue of type "pointer to `T1`" to the type "pointer to `T2`" (where ... the alignment requirements of `T1` are an integer multiple of those of `T2`) and back to its original type yields the original pointer value...

The same change would also be needed in paragraph 9.

#### 473. Block-scope declarations of allocator functions

Section: 5.3.4 [expr.new] Status: open Submitter: John Spicer Date: 12 Jul 2004

Looking up `operator new` in a new-expression uses a different mechanism from ordinary lookup. According to 5.3.4 [expr.new] paragraph 9,

> If the new-expression begins with a unary `::` operator, the allocation function's name is looked up in the global scope. Otherwise, if the allocated type is a class type `T` or array thereof, the allocation function's name is looked up in the scope of `T`. If this lookup fails to find the name, or if the allocated type is not a class type, the allocation function's name is looked up in the global scope.

Note in particular that the scope in which the new-expression occurs is not considered. For example,

        void f() {
            void* operator new(std::size_t, void*);
            int* i = new int;    // okay?
        }

In this example, the implicit reference to `operator new(std::size_t)` finds the global declaration, even though the block-scope declaration of `operator new` with a different signature would hide it from an ordinary reference.

This seems strange; either the block-scope declaration should be ill-formed or it should be found by the lookup.

Notes from October 2004 meeting:

The CWG agreed that the block-scope declaration should not be found by the lookup in a new-expression. It would, however, be found by ordinary lookup if the allocation function were invoked explicitly.

#### 196. Arguments to deallocation functions

Section: 5.3.5 [expr.delete] Status: open Submitter: Matt Austern Date: 20 Jan 2000

5.3.4 [expr.new] paragraph 10 says that the result of an array allocation function and the value of the array new-expression from which it was invoked may be different, allowing for space preceding the array to be used for implementation purposes such as saving the number of elements in the array. However, there is no corresponding description of the relationship between the operand of an array delete-expression and the argument passed to its deallocation function.

3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 3 does state that

> the value supplied to `operator delete[](void*)` in the standard library shall be one of the values returned by a previous invocation of either `operator new[](std::size_t)` or `operator new[](std::size_t, const std::nothrow_t&)` in the standard library.

This statement might be read as requiring an implementation, when processing an array delete-expression and calling the deallocation function, to perform the inverse of the calculation applied to the result of the allocation function to produce the value of the new-expression. (5.3.5 [expr.delete] paragraph 2 requires that the operand of an array delete-expression "be the pointer value which resulted from a previous array new-expression.") However, it is not completely clear whether the "shall" expresses an implementation requirement or a program requirement (or both). Furthermore, there is no direct statement about user-defined deallocation functions.

Suggested resolution: A note should be added to 5.3.5 [expr.delete] to clarify that any offset added in an array new-expression must be subtracted in the array delete-expression.

#### 242. Interpretation of old-style casts

Section: 5.4 [expr.cast] Status: open Submitter: Mike Miller Date: 30 Aug 2000

The meaning of an old-style cast is described in terms of `const_cast`, `static_cast`, and `reinterpret_cast` in 5.4 [expr.cast] paragraph 5. Ignoring `const_cast` for the moment, it basically says that if the conversion performed by a given old-style cast is one of those performed by `static_cast`, the conversion is interpreted as if it were a `static_cast`; otherwise, it's interpreted as if it were a `reinterpret_cast`, if possible. The following example is given in illustration:

        struct A {};
        struct I1 : A {};
        struct I2 : A {};
        struct D : I1, I2 {};
        A *foo( D *p ) {
    	return (A*)( p ); // ill-formed static_cast interpretation
        }

The obvious intent here is that a derived-to-base pointer conversion is one of the conversions that can be performed using `static_cast`, so `(A*)(p)` is equivalent to `static_cast<A*>(p)`, which is ill-formed because of the ambiguity.

Unfortunately, the description of `static_cast` in 5.2.9 [expr.static.cast] does NOT support this interpretation. The problem is in the way 5.2.9 [expr.static.cast] lists the kinds of casts that can be performed using `static_cast`. Rather than saying something like "All standard conversions can be performed using `static_cast`," it says

> An expression e can be explicitly converted to a type `T` using a `static_cast` of the form `static_cast<T>(e)` if the declaration "`T t(e);`" is well-formed, for some invented temporary variable `t`.

Given the declarations above, the hypothetical declaration

        A* t(p);

is NOT well-formed, because of the ambiguity. Therefore the old-style cast `(A*)(p)` is NOT one of the conversions that can be performed using `static_cast`, and `(A*)(p)` is equivalent to `reinterpret_cast<A*>(p)`, which is well-formed under 5.2.10 [expr.reinterpret.cast] paragraph 7.

Other situations besides ambiguity which might raise similar questions include access violations, casting from virtual base to derived, and casting pointers-to-members when virtual inheritance is involved.

#### 583. Relational pointer comparisons against the null pointer constant

Section: 5.9 [expr.rel] Status: open Submitter: James Widman Date: 24 May 2006

In C, this is ill-formed (cf C99 6.5.8):

        void f(char* s) {
            if (s < 0) { }
        }

...but in C++, it's not. Why? Who would ever need to write `(s > 0)` when they could just as well write `(s != 0)`?

This has been in the language since the ARM (and possibly earlier); apparently it's because the pointer conversions (4.10 [conv.ptr]) need to be performed on both operands whenever one of the operands is of pointer type. So it looks like the "null-ptr-to-real-pointer-type" conversion is hitching a ride with the other pointer conversions.

#### 1256. Unevaluated operands are not necessarily constant expressions

Section: 5.19 [expr.const] Status: open Submitter: Nikolay Ivchenkov Date: 2011-03-08

The current definition of constant expressions appears to make unevaluated operands constant expressions; for example, `new char[10]` would seem to be a constant expression if it appears as the operand of `sizeof`. This seems wrong.

#### 1523. Point of declaration in range-based `for`

Section: 6.5.4 [stmt.ranged] Status: open Submitter: John Spicer Date: 2012-07-16

According to the general rule for declarations in 3.3.2 [basic.scope.pdecl] paragraph 1,

> The point of declaration for a name is immediately after its complete declarator (Clause 8 [dcl.decl]) and before its initializer (if any), except as noted below.

However, the rewritten expansion of the range-based `for` statement in 6.5.4 [stmt.ranged] paragraph 1 contradicts this general rule, so that the index variable is not visible in the range-init:

      for (int i : {i}) ;   // error: i not in scope

(See also issue 1498 for another question regarding the rewritten form of the range-based `for`.)

Notes from the October, 2012 meeting:

EWG is discussing issue 900 and the outcome of that discussion should be taken into consideration in addressing this issue.

#### 157. Omitted typedef declarator

Section: 7 [dcl.dcl] Status: open Submitter: Daveed Vandevoorde Date: 19 Aug 1999

7 [dcl.dcl] paragraph 3 reads,

> In a simple-declaration, the optional init-declarator-list can be omitted only when... the decl-specifier-seq contains either a class-specifier, an elaborated-type-specifier with a class-key (9.1 [class.name] ), or an enum-specifier. In these cases and whenever a class-specifier or enum-specifier is present in the decl-specifier-seq, the identifiers in those specifiers are among the names being declared by the declaration... In such cases, and except for the declaration of an unnamed bit-field (9.6 [class.bit] ), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration. [Example:

>         enum { };           // ill-formed
>         typedef class { };  // ill-formed

> —end example]

In the absence of any explicit restrictions in 7.1.3 [dcl.typedef] , this paragraph appears to allow declarations like the following:

        typedef struct S { };    // no declarator
        typedef enum { e1 };     // no declarator

In fact, the final example in 7 [dcl.dcl] paragraph 3 would seem to indicate that this is intentional: since it is illustrating the requirement that the decl-specifier-seq must introduce a name in declarations in which the init-declarator-list is omitted, presumably the addition of a class name would have made the example well-formed.

On the other hand, there is no good reason to allow such declarations; the only reasonable scenario in which they might occur is a mistake on the programmer's part, and it would be a service to the programmer to require that such errors be diagnosed.

#### 498. Storage class specifiers in definitions of class members

Section: 7.1.1 [dcl.stc] Status: open Submitter: Matt Austern Date: 13 Jan 2005

Suppose we've got this class definition:

        struct X {
           void f();
           static int n;
        };

I think I can deduce from the existing standard that the following member definitions are ill-formed:

        static void X::f() { }
        static int X::n;

To come to that conclusion, however, I have to put together several things in different parts of the standard. I would have expected to find an explicit statement of this somewhere; in particular, I would have expected to find it in 7.1.1 [dcl.stc]. I don't see it there, or anywhere.

Gabriel Dos Reis: Or in 3.5 [basic.link] which is about linkage. I would have expected that paragraph to say that that members of class types have external linkage when the enclosing class has an external linkage. Otherwise 3.5 [basic.link] paragraph 8:

> Names not covered by these rules have no linkage.

might imply that such members do not have linkage.

Notes from the April, 2005 meeting:

The question about the linkage of class members is already covered by 3.5 [basic.link] paragraph 5.

#### 609. What is a “top-level” cv-qualifier?

Section: 7.1.6.1 [dcl.type.cv] Status: open Submitter: Dawn Perchik Date: 5 November 2006

The phrase “top-level cv-qualifier” is used numerous times in the Standard, but it is not defined. The phrase could be misunderstood to indicate that the `const` in something like `const T&` is at the “top level,” because where it appears is the highest level at which it is permitted: `T& const` is ill-formed.

#### 144. Position of `friend` specifier

Section: 7.1.6.3 [dcl.type.elab] Status: open Submitter: Daveed Vandevoorde Date: 22 Jul 1999

7.1.6.3 [dcl.type.elab] paragraph 1 seems to impose an ordering constraint on the elements of friend class declarations. However, the general rule is that declaration specifiers can appear in any order. Should

        class C friend;

be well-formed?

#### 977. When is an enumeration type complete?

Section: 7.2 [dcl.enum] Status: open Submitter: Daniel Krügler Date: 3 October, 2009

There is disagreement among implementations as to when an enumeration type is complete. For example,

        enum E { e = E() };

is rejected by some and accepted by another. The Standard does not appear to resolve this question definitively.

See also issue 1482.

#### 987. Which declarations introduce namespace members?

Section: 7.3 [basic.namespace] Status: open Submitter: Michael Wong Date: 19 October, 2009

According to 7.3 [basic.namespace] paragraph 1,

> The name of a namespace can be used to access entities declared in that namespace; that is, the members of the namespace.

implying that all declarations in a namespace, including definitions of members of nested namespaces, explicit instantiations, and explicit specializations, introduce members of the containing namespace. 7.3.1.2 [namespace.memdef] paragraph 3 clarifies the intent somewhat:

> Every name first declared in a namespace is a member of that namespace.

However, current changes to clarify the behavior of deleted functions (which must be deleted on their “first declaration”) state that an explicit specialization of a function template is its first declaration.

#### 1021. Definitions of namespace members

Section: 7.3.1.2 [namespace.memdef] Status: open Submitter: Michael Wong Date: 2010-01-14

According to 7.3.1.2 [namespace.memdef] paragraphs 1 and 2 read,

> Members (including explicit specializations of templates (14.7.3 [temp.expl.spec])) of a namespace can be defined within that namespace.

> Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2 [namespace.qual]) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration's namespace.

It is not clear what these specifications mean for the following pair of examples:

        namespace N {
            struct A;
        }
        using N::A;
        struct A { };

Although this does not satisfy the “by explicit qualification” requirement, it is accepted by major implementations.

        struct S;
        namespace A {
            using ::S;
            struct S  { };
        }

Is this a definition “within that namespace,” or should that wording be interpreted as “directly within” the namespace?

#### 36. using-declarations in multiple-declaration contexts

Section: 7.3.3 [namespace.udecl] Status: open Submitter: Andrew Koenig Date: 20 Aug 1998

Section 7.3.3 [namespace.udecl] paragraph 8 says:

> A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed.

It contains the following example:

        namespace A {
                int i;
        }

        namespace A1 {
                using A::i;
                using A::i;             // OK: double declaration
        }

        void f()
        {
                using A::i;
                using A::i;             // error: double declaration
        }

However, if "`using A::i;`" is really a declaration, and not a definition, it is far from clear that repeating it should be an error in either context. Consider:

        namespace A {
                int i;
                void g();
        }

        void f() {
                using A::g;
                using A::g;
        }

Surely the definition of f should be analogous to

        void f() {
                void g();
                void g();
        }

which is well-formed because "`void g();`" is a declaration and not a definition.

Indeed, if the double using-declaration for `A::i` is prohibited in `f`, why should it be allowed in namespace `A1`?

Proposed Resolution (04/99): Change the comment "`// error: double declaration`" to "`// OK: double declaration`". (This should be reviewed against existing practice.)

Notes from 04/00 meeting:

The core language working group was unable to come to consensus over what kind of declaration a using-declaration should emulate. In a straw poll, 7 members favored allowing using-declarations wherever a non-definition declaration could appear, while 4 preferred to allow multiple using-declarations only in namespace scope (the rationale being that the permission for multiple using-declarations is primarily to support its use in multiple header files, which are seldom included anywhere other than namespace scope). John Spicer pointed out that `friend` declarations can appear multiple times in class scope and asked if using-declarations would have the same property under the "like a declaration" resolution.

As a result of the lack of agreement, the issue was returned to "open" status.

See also issues 56, 85, and 138..

Additional notes (January, 2005):

Some related issues have been raised concerning the following example (modified from a C++ validation suite test):

        struct A
        {
            int i;
            static int j;
        };

        struct B : A { };
        struct C : A { };

        struct D : virtual B, virtual C
        {
            using B::i;
            using C::i;
            using B::j;
            using C::j;
        };

Currently, it appears that the using-declarations of `i` are ill-formed, on the basis of 7.3.3 [namespace.udecl] paragraph 10:

> Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region (3.3 [basic.scope]) also apply to using-declarations.

Because the using-declarations of `i` refer to different objects, declaring them in the same scope is not permitted under 3.3 [basic.scope]. It might, however, be preferable to treat this case as many other ambiguities are: allow the declaration but make the program ill-formed if a name reference resolves to the ambiguous declarations.

The status of the using-declarations of `j`, however, is less clear. They both declare the same entity and thus do not violate the rules of 3.3 [basic.scope]. This might (or might not) violate the restrictions of 9.2 [class.mem] paragraph 1:

> Except when used to declare friends (11.3 [class.friend]) or to introduce the name of a member of a base class into a derived class (7.3.3 [namespace.udecl], _N3225_.11.3 [class.access.dcl]), member-declarations declare members of the class, and each such member-declaration shall declare at least one member name of the class. A member shall not be declared twice in the member-specification, except that a nested class or member class template can be declared and then later defined.

Do the using-declarations of `j` repeatedly declare the same member? Or is the preceding sentence an indication that a using-declaration is not a declaration of a member?

#### 813. `typename` in a using-declaration with a non-dependent name

Section: 7.3.3 [namespace.udecl] Status: open Submitter: UK Date: 3 March, 2009
N2800 comment UK 101

7.3.3 [namespace.udecl] paragraph 20 says,

> If a using-declaration uses the keyword `typename` and specifies a dependent name (14.6.2 [temp.dep]), the name introduced by the using-declaration is treated as a typedef-name (7.1.3 [dcl.typedef]).

This wording does not address use of `typename` in a using-declaration with a non-dependent name; the primary specification of the `typename` keyword in 14.6 [temp.res] does not appear to describe this case, either.

#### 852. using-declarations and dependent base classes

Section: 7.3.3 [namespace.udecl] Status: open Submitter: Michael Wong Date: 2 April, 2009

The status of an example like the following is unclear in the current Standard:

        struct B {
            void f();
        };
        template<typename T> struct S: T {
            using B::f;
        };

7.3.3 [namespace.udecl] does not deal explicitly with dependent base classes, but does say in paragraph 3,

> In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined. If such a using-declaration names a constructor, the nested-name-specier shall name a direct base class of the class being defined; otherwise it introduces the set of declarations found by member name lookup (10.2 [class.member.lookup], 3.4.3.1 [class.qual]).

In the definition of `S`, `B::f` is not a dependent name but resolves to an apparently unrelated class. However, because `S` could be instantiated as `S<B>`, presumably 14.6 [temp.res] paragraph 8 would apply:

> No diagnostic shall be issued for a template definition for which a valid specialization can be generated.

Note also the resolution of issue 515, which permitted a similar use of a dependent base class named with a non-dependent name.

#### 563. Linkage specification for objects

Section: 7.5 [dcl.link] Status: open Submitter: Daveed Vandevoorde Date: 8 March 2006

It is not clear whether some of the wording in 7.5 [dcl.link] that applies only to function types and names ought also to apply to object names. In particular, paragraph 3 says,

> Every implementation shall provide for linkage to functions written in the C programming language, `"C"`, and linkage to C++ functions, `"C++"`.

Nothing is said about variable names, apparently meaning that implementations need not provide C (or even C++!) linkage for variable names. Also, paragraph 5 says,

> Except for functions with C++ linkage, a function declaration without a linkage specification shall not precede the first linkage specification for that function. A function can be declared without a linkage specification after an explicit linkage specification has been seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.

There doesn't seem to be a good reason for these provisions not to apply to variable names, as well.

#### 504. Should use of a variable in its own initializer require a diagnostic?

Section: 8.3.2 [dcl.ref] Status: open Submitter: Bjarne Stroustrup Date: 14 Apr 2005

Split off from issue 453.

It is in general not possible to determine at compile time whether a reference is used before it is initialized. Nevertheless, there is some sentiment to require a diagnostic in the obvious cases that can be detected at compile time, such as the name of a reference appearing in its own initializer. The resolution of issue 453 originally made such uses ill-formed, but the CWG decided that this question should be a separate issue.

Rationale (October, 2005):

The CWG felt that this error was not likely to arise very often in practice. Implementations can warn about such constructs, and the resolution for issue 453 makes executing such code undefined behavior; that seemed to address the situation adequately.

Note (February, 2006):

Recent discussions have suggested that undefined behavior be reduced. One possibility (broadening the scope of this issue to include object declarations as well as references) was to require a diagnostic if the initializer uses the value, but not just the address, of the object or reference being declared:

        int i = i;        // Ill-formed, diagnostic required
        void* p = &p;     // Okay

#### 550. Pointer to array of unknown bound in parameter declarations

Section: 8.3.5 [dcl.fct] Status: open Submitter: Daveed Vandevoorde Date: 22 November 2005

The current wording of 8.3.5 [dcl.fct] paragraph 6 encompasses more than it should:

> If the type of a parameter includes a type of the form “pointer to array of unknown bound of `T`” or “reference to array of unknown bound of `T`,” the program is ill-formed. [Footnote: This excludes parameters of type “ptr-arr-seq `T2`” where `T2` is “pointer to array of unknown bound of `T`” and where ptr-arr-seq means any sequence of “pointer to” and “array of” derived declarator types. This exclusion applies to the parameters of the function, and if a parameter is a pointer to function or pointer to member function then to its parameters also, etc. —end footnote]

The normative wording (contrary to the intention expressed in the footnote) excludes declarations like

        template<class T> struct S {};
        void f(S<int (*)[]>);

and

        struct S {};
        void f(int(*S::*)[]);

but not

        struct S {};
        void f(int(S::*)[]);

#### 670. Copy initialization via derived-to-base conversion in the second step

Section: 8.5 [dcl.init] Status: open Submitter: Jason Merrill Date: 20 December 2007

In this example:

        struct A {};

        struct B: A {
           B(int);
           B(B&);
           B(A);
        };

        void foo(B);

        void bar() {
           foo(0);
        }

we are copy-initializing a `B` from `0`. So by 13.3.1.4 [over.match.copy] we consider all the converting constructors of `B`, and choose `B(int)` to create a `B`. Then, by 8.5 [dcl.init] paragraph 15, we direct-initialize the parameter from that temporary `B`. By 13.3.1.3 [over.match.ctor] we consider all constructors. The copy constructor cannot be called with a temporary, but `B(A)` is callable.

As far as I can tell, the Standard says that this example is well-formed, and calls `B(A)`. EDG and G++ have rejected this example with a message about the copy constructor not being callable, but I have been unsuccessful in finding anything in the Standard that says that we only consider the copy constructor in the second step of copy-initialization. I wouldn't mind such a rule, but it doesn't seem to be there. And implementing issue 391 causes G++ to start accepting the example.

This question came up before in a GCC bug report; in the discussion of that bug Nathan Sidwell said that some EDG folks explained to him why the testcase is ill-formed, but unfortunately didn't provide that explanation in the bug report.

I think the resolution of issue 391 makes this example well-formed; it was previously ill-formed because in order to bind the temporary `B(0)` to the argument of `A(const A&)` we needed to make another temporary `B`, and that's what made the example ill-formed. If we want this example to stay ill-formed, we need to change something else.

Steve Adamczyk:

I tracked down my response to Nathan at the time, and it related to my paper N1232 (on the `auto_ptr` problem). The change that came out of that paper is in 13.3.3.1 [over.best.ics] paragraph 4:

> However, when considering the argument of a user-defined conversion function that is a candidate by 13.3.1.3 [over.match.ctor] when invoked for the copying of the temporary in the second step of a class copy-initialization, or by 13.3.1.4 [over.match.copy], 13.3.1.5 [over.match.conv], or 13.3.1.6 [over.match.ref] in all cases, only standard conversion sequences and ellipsis conversion sequences are allowed.

This is intended to prevent use of more than one implicit user- defined conversion in an initialization.

I told Nathan `B(A)` can't be called because its argument would require yet another user-defined conversion, but I was wrong. I saw the conversion from `B` to `A` and immediately thought “user-defined,” but in fact because `B` is a derived class of `A` the conversion according to 13.3.3.1 [over.best.ics] paragraph 6 is a derived-to-base Conversion (even though it will be implemented by calling a copy constructor).

So I agree with you: with the analysis above and the change for issue 391 this example is well-formed. We should discuss whether we want to make a change to keep it ill-formed.

#### 511. POD-structs with template assignment operators

Section: 9 [class] Status: open Submitter: Alisdair Meredith Date: 19 Mar 2005

A POD-struct is not permitted to have a user-declared copy assignment operator (9 [class] paragraph 4). However, a template assignment operator is not considered a copy assignment operator, even though its specializations can be selected by overload resolution for performing copy operations (12.8 [class.copy] paragraph 9 and especially footnote 114). Consequently, `X` in the following code is a POD, notwithstanding the fact that copy assignment (for a non-const operand) is a member function call rather than a bitwise copy:

        struct X {
          template<typename T> const X& operator=(T&);
        };
        void f() {
          X x1, x2;
          x1 = x2;  // calls X::operator=<X>(X&)
        }

Is this intentional?

#### 1397. Class completeness in non-static data member initializers

Section: 9.2 [class.mem] Status: open Submitter: Jason Merrill Date: 2011-09-23

In Bloomington there was general agreement that given a class that uses non-static data member initializers, the exception-specification for the default constructor depends on whether those initializers are noexcept. However, according to 9.2 [class.mem] paragraph 2, the class is regarded as complete within the brace-or-equal-initializers for non-static data members.

This suggests that we need to finish processing the class before parsing the NSDMI, but our direction on issue 1351 suggests that we need to parse the NSDMI in order to finish processing the class. Can't have both...

#### 57. Empty unions

Section: 9.5 [class.union] Status: open Submitter: Steve Adamczyk Date: 13 Oct 1998

There doesn't seem to be a prohibition in 9.5 [class.union] against a declaration like

        union { int : 0; } x;

Should that be valid? If so, 8.5 [dcl.init] paragraph 5 third bullet, which deals with default-initialization of unions, should say that no initialization is done if there are no data members.

What about:

        union { } x;
        static union { };

If the first example is well-formed, should either or both of these cases be well-formed as well?

(See also the resolution for issue 151.)

Notes from 10/00 meeting: The resolution to issue 178, which was accepted as a DR, addresses the first point above (default initialization). The other questions have not yet been decided, however.

#### 380. Definition of "ambiguous base class" missing

Section: 10.2 [class.member.lookup] Status: open Submitter: Jason Merrill Date: 22 Oct 2002

The term "ambiguous base class" doesn't seem to be actually defined anywhere. 10.2 [class.member.lookup] paragraph 7 seems like the place to do it.

#### 600. Does access control apply to members or to names?

Section: 11 [class.access] Status: open Submitter: Alisdair Meredith Date: 3 October 2006

Referring to a private member of a class, 11 [class.access] paragraph 1 says,

> its name can be used only by members and friends of the class in which it is declared.

That wording does not appear to reflect the intent of access control, however. Consider the following:

        struct S {
            void f(int);
        private:
            void f(double);
        };

        void g(S* sp) {
            sp->f(2);        // Ill-formed?
        }

The statement from 11 [class.access] paragraph 1 says that the name `f` can be used only by members and friends of `S`. Function `g` is neither, and it clearly contains a use of the name `f`. That appears to make it ill-formed, in spite of the fact that overload resolution will select the public member.

A related question is whether the use of the term “name” in the description of the effect of access control means that it does not apply to constructors and destructors, which do not have names.

Mike Miller: The phrase “its name can be used” should be understood as “it can be referred to by name.” Paragraph 4, among other places, makes it clear that access control is applied after overload resolution. The “name” phrasing is there to indicate that access control does not apply where the name is not used (in a call via a pointer, for example).

#### 360. Using-declaration that reduces access

Section: 11.2 [class.access.base] Status: open Submitter: Steve Clamage Date: 4 June 2002

I have heard a claim that the following code is valid, but I don't see why.

      struct A {
        int foo ();
      };

      struct B: A {
      private:
        using A::foo;
      };

      int main ()
      {
        return B ().foo ();
      }

It seems to me that the using declaration in B should hide the public foo in A. Then the call to B::foo should fail because B::foo is not accessible in main.

Am I missing something?

Steve Adamczyk: This is similar to the last example in 11.2 [class.access.base]. In prose, the rule is that if you have access to cast to a base class and you have access to the member in the base class, you are given access in the derived class. In this case, A is a public base class of B and foo is public in A, so you can access foo through a B object. The actual permission for this is in the fourth bullet in 11.2 [class.access.base] paragraph 4.

The wording changes for issue 9 make this clearer, but I believe even without them this example could be discerned to be valid.

See my paper J16/96-0034, WG21/N0852 on this topic.

Steve Clamage: But a using-declaration is a declaration (7.3.3 [namespace.udecl]). Compare with

      struct B : A {
      private:
        int foo();
      };

In this case, the call would certainly be invalid, even though your argument about casting B to an A would make it OK. Your argument basically says that an access adjustment to make something less accessible has no effect. That also doesn't sound right.

Steve Adamczyk: I agree that is strange. I do think that's what 11.2 [class.access.base] says, but perhaps that's not what we want it to say.

#### 718. Non-class, non-function friend declarations

Section: 11.3 [class.friend] Status: open Submitter: John Spicer Date: 18 September, 2008

With the change from a scope-based to an entity-based definition of friendship (see issues 372 and 580), it could well make sense to grant friendship to enumerations and variables, for example:

        enum E: int;
        class C {
          static const int i = 5;  // Private
          friend E;
          friend int x;
        };
        enum E { e = C::i; };      // OK: E is a friend
        int x = C::i;              // OK: x is a friend

According to the current wording of 11.3 [class.friend] paragraph 3, the friend declaration of `E` is well-formed but ignored, while the friend declaration of `x` is ill-formed.

#### 581. Can a templated constructor be explicitly instantiated or specialized?

Section: 12.1 [class.ctor] Status: open Submitter: Mark Mitchell Date: 19 May 2006

Although it is not possible to specify a constructor's template arguments in a constructor invocation (because the constructor has no name but is invoked by use of the constructor's class's name), it is possible to “name” the constructor in declarative contexts: per 3.4.3.1 [class.qual] paragraph 2,

> In a lookup in which the constructor is an acceptable lookup result, if the nested-name-specifier nominates a class `C`, and the name specified after the nested-name-specifier, when looked up in `C`, is the injected-class-name of `C` (clause 9 [class]), the name is instead considered to name the constructor of class `C`... Such a constructor name shall be used only in the declarator-id of a declaration that names a constructor.

Should it therefore be possible to specify template-arguments for a templated constructor in an explicit instantiation or specialization? For example,

        template <int dim> struct T {};
        struct X {
          template <int dim> X (T<dim> &) {};
        };

        template X::X<> (T<2> &);

If so, that should be clarified in the text. In particular, 12.1 [class.ctor] paragraph 1 says,

> Constructors do not have names. A special declarator syntax using an optional sequence of function-specifiers (7.1.2 [dcl.fct.spec]) followed by the constructor’s class name followed by a parameter list is used to declare or define the constructor.

This certainly sounds as if the parameter list must immediately follow the class name, with no allowance for a template argument list.

It would be worthwhile in any event to revise this wording to utilize the “considered to name” approach of 3.4.3.1 [class.qual]; as it stands, this wording sounds as if the following would be acceptable:

        struct S {
            S();
        };
        S() { }    // qualified-id not required?

Notes from the October, 2006 meeting:

It was observed that explicitly specifying the template arguments in a constructor declaration is never actually necessary because the arguments are, by definition, all deducible and can thus be omitted.

#### 1299. “Temporary objects” vs “temporary expressions”

Section: 12.2 [class.temporary] Status: open Submitter: Johannes Schaub Date: 2011-04-16

The Standard is insufficiently precise in dealing with temporaries. It is not always clear when the term “temporary” is referring to an expression whose result is a prvalue and when it is referring to a temporary object.

#### 1568. Temporary lifetime extension with intervening cast

Section: 12.2 [class.temporary] Status: open Submitter: Steve Adamczyk Date: 2012-10-11

According to 12.2 [class.temporary] paragraphs 4-5,

> There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression...

> The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference...

It is not clear whether this applies to an example like the following:

      struct S { };
      const S& r = (const S&)S();

In one sense `r` is being bound to the temporary because the object to which `r` refers is the temporary object. From another perspective, however, `r` is being bound not to a temporary but to the lvalue expression `(const S&)S()`, or, more precisely, to the invented temporary variable described in 5.2.9 [expr.static.cast] paragraph 4:

> Otherwise, an expression `e` can be explicitly converted to a type `T` using a `static_cast` of the form `static_cast<T>(e)` if the declaration `T t(e);` is well-formed, for some invented temporary variable `t` (8.5 [dcl.init]). The effect of such an explicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion.

(Since the invented variable `t` is called a “temporary,” perhaps the intent is that its lifetime is extended to that of `r`, and then the lifetime of the `S()` temporary would be that of `t`. However, this reasoning is tenuous, and it may be better to make the intent explicitly clear.)

#### 344. Naming destructors

Section: 12.4 [class.dtor] Status: open Submitter: Jamie Schmeiser Date: 25 April 2002

Note that destructors suffer from similar problems as those of constructors dealt with in issue 194 and in 263 (constructors as friends). Also, the wording in 12.4 [class.dtor], paragraph 1 does not permit a destructor to be defined outside of the memberlist.

Change 12.4 [class.dtor], paragraph 1 from

> ...A special declarator syntax using an optional function-specifier (7.1.2 [dcl.fct.spec]) followed by `~` followed by the destructor's class name followed by an empty parameter list is used to declare the destructor in a class definition. In such a declaration, the `~` followed by the destructor's class name can be enclosed in optional parentheses; such parentheses are ignored....

to

> ...A special declarator syntax using an optional sequence of function-specifiers (7.1.2 [dcl.fct.spec]), an optional friend keyword, an optional sequence of function-specifiers (7.1.2 [dcl.fct.spec]) followed by an optional `::` scope-resolution-operator followed by an optional nested-name-specifier followed by `~` followed by the destructor's class name followed by an empty parameter list is used to declare the destructor. The optional nested-name-specifier shall not be specified in the declaration of a destructor within the member-list of the class of which the destructor is a member. In such a declaration, the optional `::` scope-resolution-operator followed by an optional nested-name-specifier followed by `~` followed by the destructor's class name can be enclosed in optional parentheses; such parentheses are ignored....

#### 607. Lookup of mem-initializer-ids

Section: 12.6.2 [class.base.init] Status: open Submitter: Richard Corden Date: 5 December 2006

In an example like,

        struct Y {};

        template <typename T>
        struct X : public virtual Y { };

        template <typename T>
        class A : public X<T> {
          template <typename S>
          A (S)
            : S ()
          {
          }
        };

        template A<int>::A (Y);

Should `S` be found? (`S` is a dependent name, so if it resolves to a base class type in the instantiated template, it should satisfy the requirements.) All the compilers I tried allowed this example, but 12.6.2 [class.base.init] paragraph 2 says,

> Names in a mem-initializer-id are looked up in the scope of the constructor’s class and, if not found in that scope, are looked up in the scope containing the constructor’s definition.

The name `S` is not declared in those scopes.

Mike Miller: Here's another example that is accepted by most/all compilers but not by the current wording:

        namespace N {
          struct B { B(int); };
          typedef B typedef_B;
          struct D: B {
            D();
          };
        }

        N::D::D(): typedef_B(0) { }

Except for the fact that the constructor function parameter names are ignored (see paragraph 7), what the compilers seem to be doing is essentially ordinary unqualified name lookup.

Notes from the October, 2009 meeting:

The eventual resolution of this issue should take into account the template parameter scope introduced by the resolution of issue 481.

#### 6. Should the optimization that allows a class object to alias another object also allow the case of a parameter in an inline function to alias its argument?

Section: 12.8 [class.copy] Status: open Submitter: unknown Date: unknown

[Picked up by evolution group at October 2002 meeting.]

(See also paper J16/99-0005 = WG21 N1182.)

At the London meeting, 12.8 [class.copy] paragraph 31 was changed to limit the optimization described to only the following cases:

- the source is a temporary object
- the return value optimization

One other case was deemed desirable as well:

- aliasing a parameter in an inline function call to the function call argument.

However, there are cases when this aliasing was deemed undesirable and, at the London meeting, the committee was not able to clearly delimit which cases should be allowed and which ones should be prohibited.

Can we find an appropriate description for the desired cases?

Rationale (04/99): The absence of this optimization does not constitute a defect in the Standard, although the proposed resolution in the paper should be considered when the Standard is revised.

Note (March, 2008):

The Evolution Working Group has accepted the intent of this issue and referred it to CWG for action (not for C++0x). See paper J16/07-0033 = WG21 N2173.

Notes from the June, 2008 meeting:

The CWG decided to take no action on this issue until an interested party produces a paper with analysis and a proposal.

#### 1049. Copy elision through reference parameters of inline functions

Section: 12.8 [class.copy] Status: open Submitter: Jason Merrill Date: 2010-03-10

Consider the following example:

        int c;

        struct A {
           A() { ++c; }
           A(const A&) { ++c; }
        };

        struct B {
           A a;
           B(const A& a): a(a) { }
        };

        int main() {
           (B(A()));
           return c - 1;
        }

Here we would like to be able to avoid the copy and just construct the `A()` directly into the `A` subobject of `B`. But we can't, because it isn't allowed by 12.8 [class.copy] paragraph 34 bullet 3:

- when a temporary class object that has not been bound to a reference (12.2 [class.temporary]) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

The part about not being bound to a reference was added for an unrelated reason by issue 185. If that resolution were recast to require that the temporary object is not accessed after the copy, rather than banning the reference binding, this optimization could be applied.

The similar example using pass by value is also not one of the allowed cases, which could be considered part of issue 6.

#### 545. User-defined conversions and built-in operator overload resolution

Section: 13.3.1.2 [over.match.oper] Status: open Submitter: Steve Clamage Date: 31 October 2005

Consider the following example:

        class B1 {};
        typedef void (B1::*PB1) (); // memptr to B1

        class B2 {};
        typedef void (B2::*PB2) (); // memptr to B2

        class D1 : public B1, public B2 {};
        typedef void (D1::*PD) (); // memptr to D1

        struct S {
             operator PB1(); // can be converted to PD
        } s;
        struct T {
             operator PB2(); // can be converted to PD
        } t;

        void foo() {
             s == t; // Is this an error?
        }

According to 13.6 [over.built] paragraph 16, there is an `operator==` for `PD` (“For every pointer to member type...”), so why wouldn't it be used for this comparison?

Mike Miller: The problem, as I understand it, is that 13.3.1.2 [over.match.oper] paragraph 3, bullet 3, sub-bullet 3 is broader than it was intended to be. It says that candidate built-in operators must “accept operand types to which the given operand or operands can be converted according to 13.3.3.1 [over.best.ics].” 13.3.3.1.2 [over.ics.user] describes user-defined conversions as having a second standard conversion sequence, and there is nothing to restrict that second standard conversion sequence.

My initial thought on addressing this would be to say that user-defined conversion sequences whose second standard conversion sequence contains a pointer conversion or a pointer-to-member conversion are not considered when selecting built-in candidate operator functions. They would still be applicable after the hand-off to Clause 5 (e.g., in bringing the operands to their common type, 5.10 [expr.eq], or composite pointer type, 5.9 [expr.rel]), just not in constructing the list of built-in candidate operator functions.

I started to suggest restricting the second standard conversion sequence to conversions having Promotion or Exact Match rank, but that would exclude the Boolean conversions, which are needed for `!`, `&&`, and `||`. (It would have also restricted the floating-integral conversions, though, which might be a good idea. They can't be used implicitly, I think, because there would be an ambiguity among all the promoted integral types; however, none of the compilers I tested even tried those conversions because the errors I got were not ambiguities but things like “floating point operands not allowed for `%`”.)

Bill Gibbons: I recall seeing this problem before, though possibly not in committee discussions. As written this rule makes the set of candidate functions dependent on what classes have been defined, including classes not otherwise required to have been defined in order for "==" to be meaningful. For templates this implies that the set is dependent on what templates have been instantiated, e.g.

      template<class T> class U : public T { };
      U<B1> u;  // changes the set of candidate functions to include
                // operator==(U<B1>,U<B1>)?

There may be other places where the existence of a class definition, or worse, a template instantiation, changes the semantics of an otherwise valid program (e.g. pointer conversions?) but it seems like something to be avoided.

(See also issue 954.)

#### 418. Imperfect wording on error on multiple default arguments on a called function

Section: 13.3.3 [over.match.best] Status: open Submitter: Chris Bowler Date: 27 May 2003

According to 13.3.3 [over.match.best] paragraph 4, the following program appears to be ill-formed:

      void f(int, int=0);
      void f(int=0, int);

      void g() {
        f();
      }

Though I do not expect this is the intent of this paragraph in the standard.

13.3.3 [over.match.best] paragraph 4:

> If the best viable function resolves to a function for which multiple declarations were found, and if at least two of these declarations or the declarations they refer to in the case of using-declarations specify a default argument that made the function viable, the program is ill-formed. [Example:

>     namespace A {
>       extern "C" void f(int = 5);
>     }
>     namespace B {
>       extern "C" void f(int = 5);
>     }
>     using A::f;
>     using B::f;
>     void use() {
>     f(3); //OK, default argument was not used for viability
>     f(); //Error: found default argument twice
>     }

> end example]

#### 1459. Reference-binding tiebreakers in overload resolution

Section: 13.3.3.2 [over.ics.rank] Status: open Submitter: Jason Merrill Date: 2012-02-07

Both paragraph 3 and paragraph 4 of 13.3.3.2 [over.ics.rank] have overload resolution tiebreakers for reference binding. It might be possible to merge those into a single treatment.

#### 1038. Overload resolution of `&x.static_func`

Section: 13.4 [over.over] Status: open Submitter: Mike Miller Date: 2010-03-02

The Standard is not clear whether the following example is well-formed or not:

        struct S {
            static void f(int);
            static void f(double);
        };
        S s;
        void (*pf)(int) = &s.f;

According to 5.2.5 [expr.ref] paragraph 4 bullet 3, you do function overload resolution to determine whether `x.f` is a static or non-static member function. 5.3.1 [expr.unary.op] paragraph 6 says that you can only take the address of an overloaded function in a context that determines the overload to be chosen, and the initialization of a function pointer is such a context (13.4 [over.over] paragraph 1). The problem is that 13.4 [over.over] is phrased in terms of “an overloaded function name,” and this is a member access expression, not a name.

There is variability among implementations as to whether this example is accepted; some accept it as written, some only if the `&` is omitted, and some reject it in both forms.

Additional note (October, 2010):

A related question concerns an example like

        struct S {
            static void g(int*) {}
            static void g(long) {}
        } s;

        void foo() {
            (&s.g)(0L);
        }

Because the address occurs in a call context and not in one of the contexts mentioned in 13.4 [over.over] paragraph 1, the call expression in `foo` is presumably ill-formed. Contrast this with the similar example

        void g1(int*) {}
        void g1(long) {}

        void foo1() {
            (&g1)(0L);
        }

This call presumably is well-formed because 13.3.1.1 [over.match.call] applies to “the address of a set of overloaded functions.” (This was clearer in the wording prior to the resolution of issue 704: “...in this context using `&F` behaves the same as using the name `F` by itself.”) It's not clear that there's any reason to treat these two cases differently.

This question also bears on the original question of this issue, since the original wording of 13.3.1.1 [over.match.call] also described the case of an ordinary member function call like `s.g(0L)` as involving the “name” of the function, even though the postfix-expression is a member access expression and not a “name.” Perhaps the reference to “name” in 13.4 [over.over] should be similarly understood as applying to member access expressions?

#### 1549. Overloaded comma operator with `void` operand

Section: 13.5.2 [over.binary] Status: open Submitter: Nikolay Ivchenkov Date: 2012-09-04

Even though a function cannot take a parameter of type `void`, the current rules for overload resolution require consideration of overloaded operators when one operand has a user-defined or enumeration type and the other has type `void`. This can result in side effects and possibly errors, for example:

      template <class T> struct A {
        T t;
        typedef T type;
      };

      struct X {
        typedef A<void> type;
      };

      template <class T> void operator ,(typename T::type::type, T) {}

      int main() {
        X(), void(); // OK
        void(), X(); // error: A<void> is instantiated with a field of
                     // type void
      }

#### 954. Overload resolution of conversion operator templates with built-in types

Section: 13.6 [over.built] Status: open Submitter: Steve Clamage Date: 19 August, 2009

Consider the following example:

        struct NullClass {
            template<typename T> operator T () { return 0 ; }
        };

        int main() {
            NullClass n;
            n==5;        // #1
            return 0;
        }

The comparison at #1 is, according to the current Standard, ambiguous. According to 13.6 [over.built] paragraph 12, the candidates for `operator==(L, R)` include functions “for every pair of promoted arithmetic types,” so `L` could be either `int` or `long`, and the conversion operator template will provide an exact match for either.

Some implementations unambiguously choose the `int` candidate. Perhaps the overload resolution rules could be tweaked to prefer candidates in which `L` and `R` are the same type?

(See also issue 545.)

#### 110. Can template functions and classes be declared in the same scope?

Section: 14 [temp] Status: open Submitter: John Spicer Date: 28 Apr 1999

According to 14 [temp] paragraph 5,

> Except that a function template can be overloaded either by (non-template) functions with the same name or by other function templates with the same name (14.8.3 [temp.over] ), a template name declared in namespace scope or in class scope shall be unique in that scope.

3.3.10 [basic.scope.hiding] paragraph 2 agrees that only functions, not function templates, can hide a class name declared in the same scope:

> A class name (9.1 [class.name] ) or enumeration name (7.2 [dcl.enum] ) can be hidden by the name of an object, function, or enumerator declared in the same scope.

However, 3.3 [basic.scope] paragraph 4 treats functions and template functions together in this regard:

> Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,
> - they shall all refer to the same entity, or all refer to functions and function templates; or
> - exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same object or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden

John Spicer: You should be able to take an existing program and replace an existing function with a function template without breaking unrelated parts of the program. In addition, all of the compilers I tried allow this usage (EDG, Sun, egcs, Watcom, Microsoft, Borland). I would recommend that function templates be handled exactly like functions for purposes of name hiding.

Martin O'Riordan: I don't see any justification for extending the purview of what is decidedly a hack, just for the sake of consistency. In fact, I think we should go further and in the interest of consistency, we should deprecate the hack, scheduling its eventual removal from the C++ language standard.

The hack is there to allow old C programs and especially the 'stat.h' file to compile with minimum effort (also several other Posix and X headers). People changing such older programs have ample opportunity to "do it right". Indeed, if you are adding templates to an existing program, you should probably be placing your templates in a 'namespace', so the issue disappears anyway. The lookup rules should be able to provide the behaviour you need without further hacking.

#### 1463. `extern "C"` alias templates

Section: 14 [temp] Status: open Submitter: Daveed Vandevoorde Date: 2011-08-19

Currently 14 [temp] paragraph 4 forbids any template from having C linkage. Should alias templates be exempt from this prohibition, since they do not have any linkage?

#### 343. Make `template` optional in contexts that require a type

Section: 14.2 [temp.names] Status: open Submitter: Steve Adamczyk Date: 23 April 2002

By analogy with `typename`, the keyword `template` used to indicate that a dependent name will be a template name should be optional in contexts where a type is required, e.g., base class lists. We could also consider member and parameter declarations.

This was suggested by issue 314.

#### 579. What is a “nested” `>` or `>>`?

Section: 14.2 [temp.names] Status: open Submitter: Daveed Vandevoorde Date: 11 May 2006

The Standard does not normatively define which `>` and `>>` tokens are to be taken as closing a template-argument-list; instead, 14.2 [temp.names] paragraph 3 uses the undefined and imprecise term “non-nested:”

> When parsing a template-id, the first non-nested `>` is taken as the end of the template-argument-list rather than a greater-than operator. Similarly, the first non-nested `>>` is treated as two consecutive but distinct `>` tokens, the first of which is taken as the end of the template-argument-list and completes the template-id.

The (non-normative) footnote clarifies that

> A `>` that encloses the type-id of a `dynamic_cast`, `static_cast`, `reinterpret_cast` or `const_cast`, or which encloses the template-arguments of a subsequent template-id, is considered nested for the purpose of this description.

Aside from the questionable wording of this footnote (e.g., in what sense does a single terminating character “enclose” anything, and is a nested template-id “subsequent?”) and the fact that it is non-normative, it does not provide a complete definition of what “nesting” is intended to mean. For example, is the first `>` in this putative template-id “nested” or not?

        X<a ? b > c : d>

#### 440. Allow implicit pointer-to-member conversion on nontype template argument

Section: 14.3 [temp.arg] Status: open Submitter: David Abrahams Date: 13 Nov 2003

None of my compilers accept this, which surprised me a little. Is the base-to-derived member function conversion considered to be a runtime-only thing?

      template <class D>
      struct B
      {
          template <class X> void f(X) {}
          template <class X, void (D::*)(X) = &B<D>::f<X> >
          struct row {};
      };
      struct D : B<D>
      {
          void g(int);
          row<int,&D::g> r1;
          row<char*> r2;
      };

John Spicer: This is not among the permitted conversions listed in 14.3.

I'm not sure there is a terribly good reason for that. Some of the template argument rules for external entities were made conservatively because of concerns about issues of mangling template argument names.

David Abrahams: I'd really like to see that restriction loosened. It is a serious inconvenience because there appears to be no way to supply a usable default in this case. Zero would be an OK default if I could use the function pointer's equality to zero as a compile-time switch to choose an empty function implementation:

      template <bool x> struct tag {};

      template <class D>
      struct B
      {
          template <class X> void f(X) {}

          template <class X, void (D::*pmf)(X) = 0 >
          struct row {
              void h() { h(tag<(pmf == 0)>(), pmf); }
              void h(tag<1>, ...) {}
              void h(tag<0>, void (D::*q)(X)) { /*something*/}
          };
      };

      struct D : B<D>
      {
          void g(int);
          row<int,&D::g> r1;
          row<char*> r2;
      };

But there appears to be no way to get that effect either. The result is that you end up doing something like:

          template <class X, void (D::*pmf)(X) = 0 >
          struct row {
              void h() { if (pmf) /*something*/ }
          };

which invariably makes compilers warn that you're switching on a constant expression.

#### 150. Template template parameters and default arguments

Section: 14.3.3 [temp.arg.template] Status: open Submitter: Mike Miller Date: 3 Aug 1999

[Picked up by evolution group at October 2002 meeting.]

How are default template arguments handled with respect to template template parameters? Two separate questions have been raised:

1. Do default template arguments allow a template argument to match a template parameter with fewer template parameters, and can the template template parameter be specialized using the smaller number of template arguments? For example,

           template <class T, class U = int>
           class ARG { };

           template <class X, template <class Y> class PARM>
           void f(PARM<X>) { }    // specialization permitted?

           void g() {
               ARG<int> x;        // actually ARG<int, int>
               f(x);              // does ARG (2 parms, 1 with default)
                                  // match PARM (1 parm)?

   Template template parameters are deducible (14.8.2.5 [temp.deduct.type] paragraph 9), but 14.3.3 [temp.arg.template] does not specify how matching is done.

   Jack Rouse: I implemented template template parameters assuming template signature matching is analogous to function type matching. This seems like the minimum reasonable implementation. The code in the example would not be accepted by this compiler. However, template default arguments are compile time entities so it seems reasonable to relax the matching rules to allow cases like the one in the example. But I would consider this to be an extension to the language.

   Herb Sutter: An open issue in the LWG is that the standard doesn't explicitly permit or forbid implementations' adding additional template-parameters to those specified by the standard, and the LWG may be leaning toward explicitly permitting this. [Under this interpretation,] if the standard is ever modified to allow additional template-parameters, then writing "a template that takes a standard library template as a template template parameter" won't be just ugly because you have to mention the defaulted parameters; it would not be (portably) possible at all except possibly by defining entire families of overloaded templates to account for all the possible numbers of parameters `vector<>` (or anything else) might actually have. That seems unfortunate.

2. Are default arguments permitted in the template parameter list of a template template parameter? For example,

           template <template <class T, class U = int> class PARM>
           class C {
               PARM<int> pi;
           };

   Jack Rouse: I decided they could not in the compiler I support. This continues the analogy with function type matching. Also, I did not see a strong need to allow default arguments in this context.

   A class template used as a template template argument can have default template arguments from its declarations. How are the two sources of default arguments to be reconciled? The default arguments from the template template formal could override. But it could be cofusing if a template-id using the argument template, `ARG<int>`, behaves differently from a template-id using the template formal name, `FORMAL<int>`.

Rationale (10/99): Template template parameters are intended to be handled analogously to function function parameters. Thus the number of parameters in a template template argument must match the number of parameters in a template template parameter, regardless of whether any of those paramaters have default arguments or not. Default arguments are allowed for the parameters of a template template parameter, and those default arguments alone will be considered in a specialization of the template template parameter within a template definition; any default arguments for the parameters of a template template argument are ignored.

Note (Mark Mitchell, February, 2006):

Perhaps it is already obvious to all, but it seems worth noting that this extension would change the meaning of conforming programs:

        struct Dense { static const unsigned int dim = 1; };

        template <template <typename> class View,
                  typename Block>
        void operator+(float, View<Block> const&);

        template <typename Block,
                  unsigned int Dim = Block::dim>
        struct Lvalue_proxy { operator float() const; };

        void test_1d (void) {
            Lvalue_proxy<Dense> p;
            float b;
            b + p;
        }

If `Lvalue_proxy` is allowed to bind to `View`, then the template `operator+` will be used to perform addition; otherwise, `Lvalue_proxy`'s implicit conversion to float, followed by the built-in addition on floats will be used.

Note (March, 2008):

The Evolution Working Group has accepted the intent of this issue and referred it to CWG for action (not for C++0x). See paper J16/07-0033 = WG21 N2173.

Notes from the June, 2008 meeting:

The CWG decided to take no action on this issue until an interested party produces a paper with analysis and a proposal.

#### 708. Partial specialization of member templates of class templates

Section: 14.5.5 [temp.class.spec] Status: open Submitter: James Widman Date: 8 Aug, 2008

The Standard does not appear to specify clearly the effect of a partial specialization of a member template of a class template. For example:

        template<class T> struct B {
             template<class U> struct A { // #1
                 void h() {}
             };
             template<class U> struct A<U*> {  // #2
                 void f() {}
             };
        };

        template<> template<class U> struct B<int>::A { // #3
             void g() {}
        };

        void q(B<int>::A<char*>& p) {
             p.f();  // #4
        }

The explicit specialization at #3 replaces the primary member template #1 of `B<int>`; however, it is not clear whether the partial specialization #2 should be considered to apply to the explicitly-specialized member template of `A<int>` (thus allowing the call to `p.f()` at #4) or whether the partial specialization will be used only for specializations of `B` that are implicitly instantiated (meaning that #4 could call `p.g()` but not `p.f()`).

#### 310. Can function templates differing only in parameter cv-qualifiers be overloaded?

Section: 14.5.6.1 [temp.over.link] Status: open Submitter: Andrei Iltchenko Date: 29 Aug 2001

I get the following error diagnostic [from the EDG front end]:

    line 8: error: function template "example<T>::foo<R,A>(A)" has
              already been declared
         R  foo(const A);
            ^

when compiling this piece of code:

    struct  example  {
       template<class R, class A>   // 1-st member template
       R  foo(A);
       template<class R, class A>   // 2-nd member template
       const R  foo(A&);
       template<class R, class A>   // 3-d  member template
       R  foo(const A);
    };

    /*template<> template<>
    int  example<char>::foo(int&);*/

    int  main()
    {
       int  (example<char>::* pf)(int&) =
          &example<char>::foo;
    }

The implementation complains that

       template<class R, class A>   // 1-st member template
       R  foo(A);
       template<class R, class A>   // 3-d  member template
       R  foo(const A);

cannot be overloaded and I don't see any reason for it since it is function template specializations that are treated like ordinary non-template functions, meaning that the transformation of a parameter-declaration-clause into the corresponding parameter-type-list is applied to specializations (when determining its type) and not to function templates.

What makes me think so is the contents of 14.5.6.1 [temp.over.link] and the following sentence from 14.8.2.1 [temp.deduct.call] "If P is a cv-qualified type, the top level cv-qualifiers of P are ignored for type deduction". If the transformation was to be applied to function templates, then there would be no reason for having that sentence in 14.8.2.1 [temp.deduct.call].

14.8.2.2 [temp.deduct.funcaddr], which my example is based upon, says nothing about ignoring the top level cv-qualifiers of the function parameters of the function template whose address is being taken.

As a result, I expect that template argument deduction will fail for the 2-nd and 3-d member templates and the 1-st one will be used for the instantiation of the specialization.

#### 402. More on partial ordering of function templates

Section: 14.5.6.2 [temp.func.order] Status: open Submitter: Nathan Sidwell Date: 7 Apr 2003

This was split off from issue 214 at the April 2003 meeting.

Nathan Sidwell: John Spicer's proposed resolution does not make the following well-formed.

      template <typename T> int Foo (T const *) {return 1;} //#1
      template <unsigned I> int Foo (char const (&)[I]) {return 2;} //#2

      int main ()
      {
        return Foo ("a") != 2;
      }

Both #1 and #2 can deduce the "a" argument, #1 deduces T as char and #2 deduces I as 2. However, neither is more specialized because the proposed rules do not have any array to pointer decay.

#1 is only deduceable because of the rules in 14.8.2.1 [temp.deduct.call] paragraph 2 that decay array and function type arguments when the template parameter is not a reference. Given that such behaviour happens in deduction, I believe there should be equivalent behaviour during partial ordering. #2 should be resolved as more specialized as #1. The following alteration to the proposed resolution of DR214 will do that.

Insert before,

- If A is a cv-qualified type, A is replaced by the cv-unqualified version of A.

the following

- If P was not originally a reference type,
  - If A is an array type, A is replaced by the pointer type produced by the array to pointer conversion
  - If A is a function type, A is replaced by the pointer type produced by the function to pointer conversion

For the example above, this change results in deducing 'T const *' against 'char const *' in one direction (which succeeds), and 'char [I]' against 'T const *' in the other (which fails).

John Spicer: I don't consider this a shortcoming of my proposed wording, as I don't think this is part of the current rules. In other words, the resolution of 214 might make it clearer how this case is handled (i.e., clearer that it is not allowed), but I don't believe it represents a change in the language.

I'm not necessarily opposed to such a change, but I think it should be reviewed by the core group as a related change and not a defect in the proposed resolution to 214.

Notes from the October 2003 meeting:

There was some sentiment that it would be desirable to have this case ordered, but we don't think it's worth spending the time to work on it now. If we look at some larger partial ordering changes at some point, we will consider this again.

#### 1157. Partial ordering of function templates is still underspecified

Section: 14.5.6.2 [temp.func.order] Status: open Submitter: CA Date: 2010-08-03
N3092 comment CA 7

14.5.6.2 [temp.func.order] paragraph 3 says,

> To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs (14.5.3 [temp.variadic]) thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.

The characteristics of the synthesized entities and how they are determined is not specified. For example, members of a dependent type referred to in non-deduced contexts are not specified to exist, even though the transformed function type would be invalid in their absence.

Example 1:

      template<typename T, typename U> struct A;
      template<typename T> void foo(A<T, typename T::u> *) { } // #1
        // synthetic T1 has member T1::u
      template <typename T> void foo(A<T, typename T::u::v> *) { } // #2
        // synthetic T2 has member T2::u and member T2::u::v
        // T in #1 deduces to synthetic T2 in partial ordering;
        // deduced A for the parameter is A<T2, T2::u> * --this is not necessarily compatible
        // with A<T2, T2::u::v> * and it does not need to be. See Note 1. The effect is that
        // (in the call below) the compatibility of B::u and B::u::v is respected.
        // T in #2 cannot be successfully deduced in partial ordering from A<T1, T1::u> *;
        // invalid type T1::u::v will be formed when T1 is substituted into non-deduced contexts.
      struct B {
        struct u { typedef u v; };
      };
      int main() {
        foo((A<B, B::u> *)0); // calls #2
      }

Note 1: Template argument deduction is an attempt to match a `P` and a deduced `A`; however, template argument deduction is not specified to fail if the `P` and the deduced `A` are incompatible. This may occur in the presence of non-deduced contexts. Notwithstanding the parenthetical statement in 14.8.2.4 [temp.deduct.partial] paragraph 9, template argument deduction may succeed in determining a template argument for every template parameter while producing a deduced `A` that is not compatible with the corresponding `P`.

Example 2:

      template <typename T, typename U, typename V> struct A;
      template <typename T>
        void foo(A<T, struct T::u, struct T::u::u> *); // #2.1
          // synthetic T1 has member non-union class T1::u
      template <typename T, typename U>
        void foo(A<T, U , U> *); // #2.2
          // synthetic T2 and U2 has no required properties
          // T in #2.1 cannot be deduced in partial ordering from A<T2, U2, U2> *;
          // invalid types T2::u and T2::u::u will be formed when T2 is substituted in nondeduced contexts.
          // T and U in #2.2 deduces to, respectively, T1 and T1::u from A<T1, T1::u, struct
    T1::u::u> * unless
          // struct T1::u::u does not refer to the injected-class-name of the class T1::u (if that is possible).
      struct B {
        struct u { };
      };
      int main() {
        foo((A<B, B::u, struct B::u::u> *)0); // calls #2.1
      }

It is, however, unclear to what extent an implementation will have to go to determine these minimal properties.

#### 1257. Instantiation via non-dependent references in uninstantiated templates

Section: 14.6 [temp.res] Status: open Submitter: Johannes Schaub Date: 2011-03-09

The Standard does not appear to specify whether a non-dependent reference to a template specialization in a template definition that is never instantiated causes the implicit instantiation of the referenced specialization.

#### 186. Name hiding and template template-parameters

Section: 14.6.1 [temp.local] Status: open Submitter: John Spicer Date: 11 Nov 1999

The standard prohibits a class template from having the same name as one of its template parameters (14.6.1 [temp.local] paragraph 4). This prohibits

        template <class X> class X;

for the reason that the template name would hide the parameter, and such hiding is in general prohibited.

Presumably, we should also prohibit

        template <template <class T> class T> struct A;

for the same reason.

#### 459. Hiding of template parameters by base class members

Section: 14.6.1 [temp.local] Status: open Submitter: Daveed Vandevoorde Date: 2 Feb 2004

Currently, member of nondependent base classes hide references to template parameters in the definition of a derived class template.

Consider the following example:

       class B {
          typedef void *It;    // (1)
          // ...
        };

        class M: B {};

        template<typename> X {};

        template<typename It> struct S   // (2)
            : M, X<It> {   // (3)
          S(It, It);   // (4)
          // ...
        };

As the C++ language currently stands, the name "It" in line (3) refers to the template parameter declared in line (2), but the name "It" in line (4) refers to the typedef in the private base class (declared in line (1)).

This situation is both unintuitive and a hindrance to sound software engineering. (See also the Usenet discussion at http://tinyurl.com/32q8d .) Among other things, it implies that the private section of a base class may change the meaning of the derived class, and (unlike other cases where such things happen) there is no way for the writer of the derived class to defend the code against such intrusion (e.g., by using a qualified name).

Changing this can break code that is valid today. However, such code would have to:

1. name a template parameter and not use it after the opening brace, and
2. use that same name to access a base-class name within the braces.

I personally have no qualms breaking such a program.

It has been suggested to make situations like these ill-formed. That solution is unattractive however because it still leaves the writer of a derived class template without defense against accidental name conflicts with base members. (Although at least the problem would be guaranteed to be caught at compile time.) Instead, since just about everyone's intuition agrees, I would like to see the rules changed to make class template parameters hide members of the same name in a base class.

See also issue 458.

Notes from the March 2004 meeting:

We have some sympathy for a change, but the current rules fall straightforwardly out of the lookup rules, so they're not “wrong.” Making private members invisible also would solve this problem. We'd be willing to look at a paper proposing that.

Additional discussion (April, 2005):

John Spicer: Base class members are more-or-less treated as members of the class, [so] it is only natural that the base [member] would hide the template parameter.

Daveed Vandevoorde: Are base class members really “more or less” members of the class from a lookup perspective? After all, derived class members can hide base class members of the same name. So there is some pretty definite boundary between those two sets of names. IMO, the template parameters should either sit between those two sets, or they should (for lookup purposes) be treated as members of the class they parameterize (I cannot think of a practical difference between those two formulations).

John Spicer: How is [hiding template parameters] different from the fact that namespace members can be hidden by private parts of a base class? The addition of `int C` to `N::A` breaks the code in namespace `M` in this example:

        namespace N {
           class A {
        private:
             int C;
           };
        }

        namespace M {
           typedef int C;
           class B : public N::A {
             void f() {
                 C c;
             }
           };
        }

Daveed Vandevoorde: C++ has a mechanism in place to handle such situations: qualified names. There is no such mechanism in place for template parameters.

Nathan Myers: What I see as obviously incorrect ... is simply that a name defined right where I can see it, and directly attached to the textual scope of `B`'s class body, is ignored in favor of something found in some other file. I don't care that `C1` is defined in `A`, I have a `C1` right here that I have chosen to use. If I want `A::C1`, I can say so.

I doubt you'll find any regular C++ coder who doesn't find the standard behavior bizarre. If the meaning of any code is changed by fixing this behavior, the overwhelming majority of cases will be mysterious bugs magically fixed.

John Spicer: I have not heard complaints that this is actually a cause of problems in real user code. Where is the evidence that the status quo is actually causing problems?

In this example, the `T2` that is found is the one from the base class. I would argue that this is natural because base class members are found as part of the lookup in class `B`:

        struct A {
                 typedef int T2;
        };
        template <class T2> struct B : public A {
                 typedef int T1;
                 T1 t1;
                 T2 t2;
        };

This rule that base class members hide template parameters was formalized about a dozen years ago because it fell out of the principle that base class members should be found at the same stage of lookup as derived class members, and that to do otherwise would be surprising.

Gabriel Dos Reis: The bottom line is that:

1. the proposed change is a silent change of meaning;
2. the proposed change does not make the language any more regular; the current behavior is consistent with everything else, however “surprising” that might be;
3. the proposed change does have its own downsides.

Unless presented with real major programming problems the current rules exhibit, I do not think the simple rule “scopes nest” needs a change that silently mutates program meaning.

Mike Miller: The rationale for the current specification is really very simple:

1. “Unless redeclared in the derived class, members of a base class are also considered to be members of the derived class.” (10 [class.derived] paragraph 2)
2. In class scope, members hide nonmembers.

That's it. Because template parameters are not members, they are hidden by member names (whether inherited or not). I don't find that “bizarre,” or even particularly surprising.

I believe these rules are straightforward and consistent, so I would be opposed to changing them. However, I am not unsympathetic toward Daveed's concern about name hijacking from base classes. How about a rule that would make a program ill-formed if a direct or inherited member hides a template parameter?

Unless this problem is a lot more prevalent than I've heard so far, I would not want to change the lookup rules; making this kind of collision a diagnosable error, however, would prevent hijacking without changing the lookup rules.

Erwin Unruh: I have a different approach that is consistent and changes the interpretation of the questionable code. At present lookup is done in this sequence:

block scope
derived class scope
base class scope
template parameters
namespace scope

If we change this order to

template parameters
block scope
derived class scope
base class scope
namespace scope

it is still consistent in that no lookup is placed between the base class and the derived class. However, it introduces another inconsistency: now scopes do not nest the same way as curly braces nest — but base classes are already inconsistent this way.

Nathan Myers: This looks entirely satisfactory. If even this seems like too big a change, it would suffice to say that finding a different name by this search order makes the program ill-formed. Of course, a compiler might issue only a portability warning in that case and use the name found Erwin's way, anyhow.

Gabriel Dos Reis: It is a simple fact, even without templates, that a writer of a derived class cannot protect himself against declaration changes in the base class.

Richard Corden: If a change is to be made, then making it ill-formed is better than just changing the lookup rules.

        struct B
        {
          typedef int T;
          virtual void bar (T const & );
        };

        template <typename T>
        struct D : public B
        {
          virtual void bar (T const & );
        };

        template class D<float>;

I think changing the semantics of the above code silently would result in very difficult-to-find problems.

Mike Miller: Another case that may need to be considered in deciding on Erwin's suggestion or the “ill-formed” alternative is the treatment of `friend` declarations described in 3.4.1 [basic.lookup.unqual] paragraph 10:

        struct A {
            typedef int T;
            void f(T);
        };
        template<typename T> struct B {
            friend void A::f(T);  // Currently T is A::T
        };

Notes from the October, 2005 meeting:

The CWG decided not to consider a change to the existing rules at this time without a paper exploring the issue in more detail.

#### 1028. Dependent names in non-defining declarations

Section: 14.6.4 [temp.dep.res] Status: open Submitter: Sean Hunt Date: 2010-02-03

The current wording of 14.6.4 [temp.dep.res] seems to assume that dependent names can only appear in the definition of a template:

> In resolving dependent names, names from the following sources are considered:

> - Declarations that are visible at the point of definition of the template.

> - Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1 [temp.point]) and from the definition context.

However, dependent names can occur in non-defining declarations of the template as well; for instance,

        template<typename T>
        T foo(T, decltype(bar(T())));

`bar` needs to be looked up, even though there is no definition of `foo` in the translation unit.

Additional note (February, 2011):

The resolution of this issue can't simply replace the word “definition” with the word “declaration,” mutatis mutandis, because there can be multiple declarations in a translation unit (which isn't true of “the definition”). As a result, the issue was moved back to "open" status for further consideration.

#### 1500. Name lookup of dependent conversion function

Section: 14.6.4.2 [temp.dep.candidate] Status: open Submitter: Johannes Schaub Date: 2012-04-27

Consider the following example:

      template<typename T>
      struct A {
       operator int() { return 0; }

       void f() {
        operator T();
       }
      };

      int main() {
       A<int> a;
       a.f();
      }

One might expect this to call `operator int` when instantiating. But since `operator T` is a dependent name, it is looked up by unqualified lookup only in the definition context, where it will find no declaration. Argument-dependent lookup will not find anything in the instantiation context either, so this code is ill-formed. If we change `operator int()` to `operator T()`, which is a seemingly unrelated change, the code becomes well-formed.

There is implementation variability on this point.

#### 1378. When is an instantiation required?

Section: 14.7.1 [temp.inst] Status: open Submitter: Jason Merrill Date: 2011-08-18

A template instantiation can be “required” without there being a need for it at link time if it can appear in a constant expression:

        template <class T> struct A {
           static const T t;
        };
        template <class T> const T A<T>::t = 0;
        template <int I> struct B { };
        int a = sizeof(B<A<int>::t>);

        template <class T> constexpr T f(T t) { return t; }
        int b = sizeof(B<f(42)>);

It seems like it might be useful to define a term other than odr-used for this sort of use, which is like odr-used but doesn't depend on potentially evaluated context or lvalue-rvalue conversions.

Nikolay Ivchenkov:

Another possibility would be to introduce the extension described in the closed issue 1272 and then change 3.2 [basic.def.odr] paragraph 2 as follows:

> An expression `E` is potentially evaluated unless it is an unevaluated operand (Clause 5 [expr]) or a subexpression thereof. if and only if

> - `E` is a full-expression, or

> - `E` appears in a context where a constant expression is required, or

> - `E` is a direct subexpression of a potentially-evaluated expression and `E` is not an unevaluated operand.

> An expression `S` is a direct subexpression of an expression `E` if and only if `S` and `E` are different expressions, `S` is a subexpression of `E`, and there is no expression `X` such that `X` differs from both `S` and `E`, `S` is a subexpression of `X`, and `X` is a subexpression of `E`. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19 [expr.const]) and the lvalue-to-rvalue conversion (4.1) is immediately applied...

> [Example:

>         template <class T> struct X {
>             static int const m = 1;
>             static int const n;
>         };
>         template <class T> int const X<T>::n = 2;

>         int main() {
>             // X<void>::m is odr-used,
>             // X<void>::m is defined implicitly
>             std::cout << X<void>::m << std::endl;

>             // X<void>::n is odr-used,
>             // X<void>::n is defined explicitly
>             std::cout << X<void>::n << std::endl;

>             // OK (issue 712 is not relevant here)
>             std::cout << (1 ? X<void>::m : X<void>::n) << std::endl;
>         }

(See also issues 712 and 1254.)

#### 293. Syntax of explicit instantiation/specialization too permissive

Section: 14.7.2 [temp.explicit] Status: open Submitter: Mark Mitchell Date: 27 Jun 2001

14.7.2 [temp.explicit] defines an explicit instantiation as

explicit-instantiation:

`template` declaration

Syntactically, that allows things like:

        template int S<int>::i = 5, S<int>::j = 7;

which isn't what anyone actually expects. As far as I can tell, nothing in the standard explicitly forbids this, as written. Syntactically, this also allows:

        template namespace N { void f(); }

although perhaps the surrounding context is enough to suggest that this is invalid.

Suggested resolution:

I think we should say:

explicit-instantiation:

type-specifier-seqopt declaratoropt `;`

[Steve Adamczyk: presumably, this should have `template` at the beginning.]

and then say that:

- The declarator can be omitted only when the type-specifier-seq consists solely of an elaborated-type-specifier for a class type, in which case the instantiation is for the named class. If the declarator is present the instantiation is for the named entity.
- The type-specifier-seq can be omitted only when the declarator is for a constructor, destructor, or conversion operator.
- The type-specifier-seq cannot define any new types.

There are similar problems in 14.7.3 [temp.expl.spec]:

explicit-specialization:

`template` <> declaration

Here, I think we want:

explicit-specialization:

decl-specifier-seqopt init-declaratoropt `;`

with similar restrictions as above.

[Steve Adamczyk: This also needs to have `template <>` at the beginning, possibly repeated.]

#### 1046. What is a “use” of a class specialization?

Section: 14.7.2 [temp.explicit] Status: open Submitter: Michael Wong Date: 2010-03-08

According to 14.7.2 [temp.explicit] paragraph 10,

> An entity that is the subject of an explicit instantiation declaration and that is also used in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.

The term “used” is too vague and needs to be defined. In particular, “use” of a class template specialization as an incomplete type — to form a pointer, for instance — should not require the presence of an explicit instantiation definition elsewhere in the program.

#### 264. Unusable template constructors and conversion functions

Section: 14.8.1 [temp.arg.explicit] Status: open Submitter: John Spicer Date: 17 Nov 2000

The note in paragraph 5 of 14.8.1 [temp.arg.explicit] makes clear that explicit template arguments cannot be supplied in invocations of constructors and conversion functions because they are called without using a name. However, there is nothing in the current wording of the Standard that makes declaring a constructor or conversion operator that is unusable because of nondeduced parameters (i.e., that would need to be specified explicitly) ill-formed. It would be a service to the programmer to diagnose this useless construct as early as possible.

#### 1386. Explicitly-specified partial argument list with multiple parameter packs

Section: 14.8.1 [temp.arg.explicit] Status: open Submitter: James Widman Date: 2011-09-01

Given

        template<class T, class U> struct A { };
        template<class... T, class ... U> void f( A<T,U>...p);

        void g() {
            f<int>(
                A<int,unsigned>(),
                A<short,unsigned short>()
                );
        }

I would expect this to work, but all the recent compilers I tried reject it, indicating deduction failure.

#### 1391. Conversions to parameter types with non deduced template arguments

Section: 14.8.1 [temp.arg.explicit] Status: open Submitter: Jason Merrill Date: 2011-09-08

According to 14.8.1 [temp.arg.explicit] paragraph 6,

> Implicit conversions (Clause 4 [conv]) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction. [Note: Template parameters do not participate in template argument deduction if they are explicitly specified...

But this isn't clear about when these conversions are done. Consider

        template<class T> struct A {
           typename T::N n;
        };
        template<class T> struct B { };

        template<class T, class T2>
        void foo(const A<T>& r); // #1
        template<class T>
        void foo(const B<T>& r); // #2

        void baz() {
           B<char> b;
           foo(b); // OK
           foo<char>(b); // error
        }

With the explicit template argument, the first parameter of #1 no longer participates in template argument deduction, so implicit conversions are done. If we check for the implicit conversion during the deduction process, we end up instantiating `A<char>`, resulting in a hard error. If we wait until later to check the conversion, we can reject #1 because `T2` is not deduced and never need to consider the conversion.

But if we just accept the parameter and leave it up to normal overload resolution to reject an unsuitable candidate, that breaks this testcase:

        template<class T>
        struct A {
           typename T::N n;
        };

        template<class T>
        struct B { };

        template <class T, class... U>
        typename A<T>::value_t bar(int, T, U...);

        template <class T>
        T bar(T, T);

        void baz()
        {
           B<char> b;
           bar(b, b);
        }

Here, if deduction succeeds, we substitute in the deduced arguments of `T = B<char>, U = { }`, and end up instantiating `A<B<char>>`, which fails.

EDG and GCC currently reject the first testcase and accept the second; clang accepts both.

Notes from the October, 2012 meeting:

The position initially favored by CWG was that implicit conversions are not considered during deduction but are only applied afterwards, so the second example is ill-formed, and that the normative wording of the referenced paragraph should be moved into the note. This approach does not handle some examples currently accepted by some implementations, however; for example:

       template <class T> struct Z {
        typedef T::x xx;
       };
       template <class T> Z<T>::xx f(void *, T);
       template <class T> void f(int, T);
       struct A {} a;
       int main() {
         f(1, a); // If the implementation rules out the first overload
                  // because of the invalid conversion from int to void*,
                  // the error instantiating Z<A> will be avoided
       }

Additional discussion is required.

#### 271. Explicit instantiation and template argument deduction

Section: 14.8.2 [temp.deduct] Status: open Submitter: John Spicer Date: 20 Feb 2001

Nicolai Josuttis sent me an example like the following:

        template <typename RET, typename T1, typename T2>
        const RET& min (const T1& a, const T2& b)
        {
    	return (a < b ? a : b);
        }
        template const int& min<int>(const int&,const int&);  // #1
        template const int& min(const int&,const int&);       // #2

Among the questions was whether explicit instantiation #2 is valid, where deduction is required to determine the type of `RET`.

The first thing I realized when researching this is that the standard does not really spell out the rules for deduction in declarative contexts (friend declarations, explicit specializations, and explicit instantiations). For explicit instantiations, 14.7.2 [temp.explicit] paragraph 2 does mention deduction, but it doesn't say which set of deduction rules from 14.8.2 [temp.deduct] should be applied.

Second, Nicolai pointed out that 14.7.2 [temp.explicit] paragraph 6 says

> A trailing template-argument can be left unspecified in an explicit instantiation provided it can be deduced from the type of a function parameter (14.8.2 [temp.deduct]).

This prohibits cases like #2, but I believe this was not considered in the wording as there is no reason not to include the return type in the deduction process.

I think there may have been some confusion because the return type is excluded when doing deduction on a function call. But there are contexts where the return type is included in deduction, for example, when taking the address of a function template specialization.

Suggested resolution:

1. Update 14.8.2 [temp.deduct] to include a section "Deducing template arguments from a declaration" that describes how deduction is done when finding a template that matches a declaration. This should, I believe, include the return type.
2. Update 14.7.2 [temp.explicit] to make reference to the new rules in 14.8.2 [temp.deduct] and remove the description of the deduction details from 14.7.2 [temp.explicit] paragraph 6.

#### 297. Which template does an explicit specialization specialize?

Section: 14.8.2 [temp.deduct] Status: open Submitter: Andrei Iltchenko Date: 7 Jul 2001

Andrei Iltchenko points out that the standard has no wording that defines how to determine which template is specialized by an explicit specialization of a function template. He suggests "template argument deduction in such cases proceeds in the same way as when taking the address of a function template, which is described in 14.8.2.2 [temp.deduct.funcaddr]."

John Spicer points out that the same problem exists for all similar declarations, i.e., friend declarations and explicit instantiation directives. Finding a corresponding placement `operator delete` may have a similar problem.

John Spicer: There are two aspects of "determining which template" is referred to by a declaration: determining the function template associated with the named specialization, and determining the values of the template arguments of the specialization.

        template <class T> void f(T);  #1
        template <class T> void f(T*); #2
        template <> void f(int*);

In other words, which `f` is being specialized (#1 or #2)? And then, what are the deduced template arguments?

14.5.6.2 [temp.func.order] does say that partial ordering is done in contexts such as this. Is this sufficient, or do we need to say more about the selection of the function template to be selected?

14.8.2 [temp.deduct] probably needs a new section to cover argument deduction for cases like this.

#### 697. Deduction rules apply to more than functions

Section: 14.8.2 [temp.deduct] Status: open Submitter: Doug Gregor Date: 6 June, 2008

14.8.2 [temp.deduct] is all about function types, but these rules also apply, e.g., when matching a class template partial specialization. We should add a note stating that we could be doing substitution into the template-id for a class template partial specialization.

Additional note (August 2008):

According to 14.5.5.1 [temp.class.spec.match] paragraph 2, argument deduction is used to determine whether a given partial specialization matches a given argument list. However, there is nothing in 14.5.5.1 [temp.class.spec.match] nor in 14.8.2 [temp.deduct] and its subsections that describes exactly how argument deduction is to be performed in this case. It would seem that more than just a note is required to clarify this processing.

#### 503. Cv-qualified function types in template argument deduction

Section: 14.8.2.1 [temp.deduct.call] Status: open Submitter: Gabriel Dos Reis Date: 22 Feb 2005

Consider the following program:

        template <typename T> int ref (T&)                { return 0; }
        template <typename T> int ref (const T&)          { return 1; }
        template <typename T> int ref (const volatile T&) { return 2; }
        template <typename T> int ref (volatile T&)       { return 4; }

        template <typename T> int ptr (T*)                { return 0; }
        template <typename T> int ptr (const T*)          { return 8; }
        template <typename T> int ptr (const volatile T*) { return 16; }
        template <typename T> int ptr (volatile T*)       { return 32; }

        void foo() {}

        int main()
        {
            return ref(foo) + ptr(&foo);
        }

The Standard appears to specify that the value returned from `main` is 2. The reason for this result is that references and pointers are handled differently in template argument deduction.

For the reference case, 14.8.2.1 [temp.deduct.call] paragraph 3 says that “If `P` is a reference type, the type referred to by `P` is used for type deduction.” Because of issue 295, all four of the types for the `ref` function parameters are the same, with no cv-qualification; overload resolution does not find a best match among the parameters and thus the most-specialized function is selected.

For the pointer type, argument deduction does not get as far as forming a cv-qualified function type; instead, argument deduction fails in the cv-qualified cases because of the cv-qualification mismatch, and only the cv-unqualified version of `ptr` survives as a viable function.

I think the choice of ignoring cv-qualifiers in the reference case but not the pointer case is very troublesome. The reason is that when one considers function objects as function parameters, it introduces a semantic difference whether the function parameter is declared a reference or a pointer. In all other contexts, it does not matter: a function name decays to a pointer and the resulting semantics are the same.

#### 1221. Partial ordering and reference collapsing

Section: 14.8.2.4 [temp.deduct.partial] Status: open Submitter: Michael Wong Date: 2010-11-08

The current partial ordering rules produce surprising results in the presence of reference collapsing.

Since partial ordering is currently based solely on the signature of the function templates, the lack of difference following substitution of the template type parameter in the following is not taken into account.

Especially unsettling is that the allegedly "more specialized" template (#2) is not a candidate in the first call where template argument deduction fails for it despite a lack of non-deduced contexts.

        template <typename T>
        void foo(T&&);  // #1

        template <typename T>
        void foo(volatile T&&);  // #2

        int main(void) {
          const int x = 0;
          foo(x);  // calls #1 with T='const int &'
          foo<const int &>(x);  // calls #2
        }

#### 92. Should exception specifications be part of the type system?

Section: 15.4 [except.spec] Status: open Submitter: Jonathan Schilling Date: 2 Feb 1999

It was tentatively agreed at the Santa Cruz meeting that exception specifications should fully participate in the type system. This change would address gaps in the current static checking of exception specifications such as

        void (*p)() throw(int);
        void (**pp)() throw() = &p;   // not currently an error

This is such a major change that it deserves to be a separate issue.

See also issues 25, 87, and 133.

#### 595. Exception specifications in templates instantiated from class bodies

Section: 15.4 [except.spec] Status: open Submitter: Daveed Vandevoorde Date: 7 September 2006

A type used in an exception specification must be complete (15.4 [except.spec] paragraph 2). The resolution of issue 437 stated that a class type appearing in an exception specification inside its own member-specification is considered to be complete. Should this also apply to exception specifications in class templates instantiated because of a reference inside the member-specification of a class? For example,

        template<class T> struct X {
            void f() throw(T) {}
        };

        struct S {
            X<S> xs;
        };

Note, January, 2012:

With the deprecation of dynamic-exception-specifications, the importance of this issue is reduced even further. The current specification is clear, and the suggested resolution is an extension. It has been suggested that the issue be closed as NAD.

Notes from the February, 2012 meeting:

The outcome of this issue will be affected by the resolution of issue 1330. See also issue 287.

#### 596. Replacing an exception object

Section: 15.5.2 [except.unexpected] Status: open Submitter: Alisdair Meredith Date: 12 September 2006

When a function throws an exception that is not in its exception-specification, `std::unexpected()` is called. According to 15.5.2 [except.unexpected] paragraph 2,

> If [`std::unexpected()`] throws or rethrows an exception that the exception-specification does not allow then the following happens: If the exception-specification does not include the class `std::bad_exception` (18.8.2 [bad.exception]) then the function `std::terminate()` is called, otherwise the thrown exception is replaced by an implementation-defined object of the type `std::bad_exception,` and the search for another handler will continue at the call of the function whose exception-specification was violated.

The “replaced by” wording is imprecise and undefined. For example, does this mean that the destructor is called for the existing exception object, or is it simply abandoned? Is the replacement in situ, so that a pointer to the existing exception object will now point to the `std::bad_exception` object?

Mike Miller: The call to `std::unexpected()` is not described as analogous to invoking a handler, but if it were, that would resolve this question; it is clearly specified what happens to the previous exception object when a new exception is thrown from a handler (15.1 [except.throw] paragraph 4).

This approach would also clarify other questions that have been raised regarding the requirements for stack unwinding. For example, 15.5.1 [except.terminate] paragraph 2 says that

> In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before `std::terminate()` is called.

This requirement could be viewed as in conflict with the statement in 15.5.2 [except.unexpected] paragraph 1 that

> If a function with an exception-specification throws an exception that is not listed in the exception-specification, the function `std::unexpected()` is called (D.11 [exception.unexpected]) immediately after completing the stack unwinding for the former function.

If it is implementation-defined whether stack unwinding occurs before calling `std::terminate()` and `std::unexpected()` is called only after doing stack unwinding, does that mean that it is implementation-defined whether `std::unexpected()` is called if there is ultimately no handler found?

Again, if invoking `std::unexpected()` were viewed as essentially invoking a handler, the answer to this would be clear, because unwinding occurs before invoking a handler.

#### 925. Type of character literals in preprocessor expressions

Section: 16.1 [cpp.cond] Status: open Submitter: Michael Wong Date: 29 June, 2009

According to 16.1 [cpp.cond] paragraph 4,

> The resulting tokens comprise the controlling constant expression which is evaluated according to the rules of 5.19 [expr.const] using arithmetic that has at least the ranges specified in 18.3 [support.limits], except that all signed and unsigned integer types act as if they have the same representation as, respectively, `intmax_t` or `uintmax_t` (_N3035_.18.4.2 [stdinth]). This includes interpreting character literals, which may involve converting escape sequences into execution character set members.

Ordinary character literals with a single c-char have the type `char`, which is neither a signed nor an unsigned integer type. Although 4.5 [conv.prom] paragraph 1 is clear that `char` values promote to `int`, regardless of whether the implementation treats `char` as having the values of `signed char` or `unsigned char`, 16.1 [cpp.cond] paragraph 4 isn't clear on whether character literals should be treated as signed or unsigned values. In C99, such literals have type `int`, so the question does not arise. If an implementation in which plain `char` has the values of `unsigned char` were to treat character literals as unsigned, an expression like `'0'-'1'` would thus have different values in C and C++, namely -1 in C and some large unsigned value in C++.

#### 268. Macro name suppression in rescanned replacement text

Section: 16.3.4 [cpp.rescan] Status: open Submitter: Bjarne Stroustrup Date: 18 Jan 2001

It is not clear from the Standard what the result of the following example should be:

>     #define NIL(xxx) xxx
>     #define G_0(arg) NIL(G_1)(arg)
>     #define G_1(arg) NIL(arg)
>     G_0(42)

The relevant text from the Standard is found in 16.3.4 [cpp.rescan] paragraph 2:

> If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's preprocessing tokens), it is not replaced. Further, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.

The sequence of expansion of `G0(42)` is as follows:

>     G0(42)
>     NIL(G_1)(42)
>     G_1(42)
>     NIL(42)

The question is whether the use of `NIL` in the last line of this sequence qualifies for non-replacement under the cited text. If it does, the result will be `NIL(42)`. If it does not, the result will be simply `42`.

The original intent of the J11 committee in this text was that the result should be `42`, as demonstrated by the original pseudo-code description of the replacement algorithm provided by Dave Prosser, its author. The English description, however, omits some of the subtleties of the pseudo-code and thus arguably gives an incorrect answer for this case.

Suggested resolution (Mike Miller): Replace the cited paragraph with the following:

> As long as the scan involves only preprocessing tokens from a given macro's replacement list, or tokens resulting from a replacement of those tokens, an occurrence of the macro's name will not result in further replacement, even if it is later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.

> Once the scan reaches the preprocessing token following a macro's replacement list — including as part of the argument list for that or another macro — the macro's name is once again available for replacement. [Example:

>         #define NIL(xxx) xxx
>         #define G_0(arg) NIL(G_1)(arg)
>         #define G_1(arg) NIL(arg)
>         G_0(42)                         // result is 42, not NIL(42)

> The reason that `NIL(42)` is replaced is that `(42)` comes from outside the replacement list of `NIL(G_1)`, hence the occurrence of `NIL` within the replacement list for `NIL(G_1)` (via the replacement of `G_1(42)`) is not marked as nonreplaceable. —end example]

(Note: The resolution of this issue must be coordinated with J11/WG14.)

Notes (via Tom Plum) from April, 2004 WG14 Meeting:

Back in the 1980's it was understood by several WG14 people that there were tiny differences between the "non-replacement" verbiage and the attempts to produce pseudo-code. The committee's decision was that no realistic programs "in the wild" would venture into this area, and trying to reduce the uncertainties is not worth the risk of changing conformance status of implementations or programs.

#### 745. Effect of ill-formedness resulting from `#error`

Section: 16.5 [cpp.error] Status: open Submitter: Clark Nelson Date: 13 November, 2008

C99 is very clear that a `#error` directive causes a translation to fail: Clause 4 paragraph 4 says,

> The implementation shall not successfully translate a preprocessing translation unit containing a `#error` preprocessing directive unless it is part of a group skipped by conditional inclusion.

C++, on the other hand, simply says that a `#error` directive “renders the program ill-formed” (16.5 [cpp.error]), and the only requirement for an ill-formed program is that a diagnostic be issued; the translation may continue and succeed. (Noted in passing: if this difference between C99 and C++ is addressed, it would be helpful for synchronization purposes in other contexts as well to introduce the term “preprocessing translation unit.”)

#### 897. `_Pragma` and extended string-literals

Section: 16.9 [cpp.pragma.op] Status: open Submitter: Daniel Krügler Date: 9 May, 2009

The specification of how the string-literal in a `_Pragma` operator is handled does not deal with the new kinds of string literals. 16.9 [cpp.pragma.op] says,

> The string literal is destringized by deleting the `L` prefix, if present, deleting the leading and trailing double-quotes, replacing each escape sequence...

The various other prefixes should either be handled or prohibited.

#### 1248. Updating Annex C to C99

Section: C.1 [diff.iso] Status: open Submitter: Jonathan Wakely Date: 2011-02-28

The description of incompatibilities with C in Annex C.1 [diff.iso] refers to C89, but there are a number of new features in C99 that should be covered.

### Issues with "Concurrency" Status

#### 1441. Unclear wording for signal handler restrictions

Section: 1.9 [intro.execution] Status: concurrency Submitter: Alisdair Meredith Date: 2012-01-06

The wording of 1.9 [intro.execution] paragraph 6 is intended to describe the values of objects upon entry to and exit from the handler — i.e., that signal handler cannot rely on non-atomic objects being in a consistent state upon entry, nor can it reliably set the value of non-atomic objects and expect that they will continue to have those values after the handler exits. However, the wording could be read as saying even during the execution of the handler it cannot set and use non-atomic objects. The wording should be clarified.

#### 1466. Visible sequences of side effects are redundant

Section: 1.10 [intro.multithread] Status: concurrency Submitter: Mark Batty Date: 2012-02-21

[The following is reproduced verbatim from WG14 DR406 as a C-liaison issue.]

It has been mathematically proved that a simplification can be made to the memory model as it is specified in the final draft of the C++11 standard. Essentially, the restriction defining visible sequence of side effects (vsse) is redundant and can be removed with no ill effects. The main motivation for doing this is that the current restriction is misleading. 5.1.2.4p22 defines vsse's:

> The visible sequence of side effects on an atomic object M, with respect to a value computation B of M, is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first side effect is visible with respect to B, and for every subsequent side effect, it is not the case that B happens before it. The value of an atomic object M, as determined by evaluation B, shall be the value stored by some operation in the visible sequence of M with respect to B.

The wording of this paragraph makes it seem as if the vsse identifies the writes that an atomic read is allowed to read from, but this is not the case. There can be writes in the vsse that cannot be read due to the coherence requirements (to be included in C, 1.10p15 through 1.10p18 in C++ N3291). Consequently this is even more confusing than it at first appears.

Also propose changing 5.1.2.4p22 to the following:

> The value of an atomic object M, as determined by evaluation B, shall be the value stored by some side effect A that modifies M, where B does not happen before A.

With a note to remind the reader of the coherence requirements:

> NOTE: The set of side effects that a given evaluation might take its value from is also restricted by the rest of the rules described here, and in particular, by the coherence requirements below

If the committee is concerned about allowing a differing text from C++11, then a note could be added to assure the reader:

> NOTE: Although the rules for multi-threaded executions differ here from those of C++11, the executions they allow are precisely the same. Visible sequences of side effects are a redundant restriction.

#### 1470. Thread migration

Section: 1.10 [intro.multithread] Status: concurrency Submitter: Detlef Vollman Date: 2012-02-14

It is not clear from the wording of 1.10 [intro.multithread] that different statements in the same function cannot be executed by different threads.