C++N4606(156)13.3.3.1.5 List-initialization sequence [over.ics.list]p330


はじめに

この一連の作業は、
「コードコンプリート」Code Complete 完全なプログラミングを目指して Steve McConnell, Microsoft Press, 2005 978-4891004552

第二章 ソフトウェア開発への理解を深めるメタファ(比喩)
https://researchmap.jp/jo4lkx7zs-1797580/#_1797580
の「コードを書く」という考え方に基づいています。

写経というよい文化があり、コンパイラやOSを写せば、C言語のかなりの部分が理解できます。いくつかのCコンパイラを写経したり、Pascalで書かれたコンパイラをC言語に書き直したりしてきました。OSは、TOPPERS/SSPという自律(freestnding)環境のOSを書き写してきました。

C言語、C++は肥大化し、それらの記述には現れない機能や関数も出ています。そこで、標準文書のコード断片をコンパイルすることにより、今、C言語、C++は何を含み、何を含まないかを確認する作業です。

出力に基づく確認は、C言語発祥の地ベル研究所から出ている3つの主なC文献
Programming language C
C traps and pit fall
The C puzzle book
のなかのThe C Puzzle Bookに基づいています。何かを出力しようとすると副作用は避けられない事があります。出力しようとしなければ起きない現象があるかもしれません。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/#mailing2016-11
N4606 Working Draft, Standard for Programming Language C++
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

n4606は、ISO/IEC JTC1 SC22 WG21の作業原案(Working Draft)です。
公式のISO/IEC 14882原本ではありません。
ISO/IEC JTC1 SC22 WG21では、可能な限り作業文書を公開し、幅広い意見を求めています。
一連の記事はコード断片をコンパイルできる形にする方法を検討してコンパイル、リンク、実行して、規格案の原文と処理系(g++, Clang++)との違いを確認し、技術内容を検討し、ISO/IEC JTC1 SC22 WG21にフィードバックするために用います。
また、CERT C++, MISRA C++等のコーディング標準のコード断片をコンパイルする際の参考にさせていただこうと考えています。CERT C++, MISRA C++が標準化の動きとの時間的なずれがあれば確認できれば幸いです。また、boostライブラリとの関連、Linux OS, TOPPERSカーネル、g++(GCC), clang++(LLVM)との関係も調査中です。
何か、抜け漏れ、耳より情報がありましたらおしらせくださると幸いです。

作業方針

1)コンパイルエラーを収集する。
2)コンパイルエラーをなくす方法を検討する。
コンパイルエラーになる例を示すだけが目的のコードは、コンパイルエラーをなくすのではなく、コンパイルエラーの種類を収集するだけにする。
文法を示すのが目的のコード場合に、コンパイルエラーをなくすのに手間がかかる場合は、順次作業します。
3)リンクエラーをなくす方法を検討する。
文法を示すのが目的のコード場合に、リンクエラーをなくすのに手間がかかる場合は、順次作業します。
4)意味のある出力を作る。
コンパイル、リンクが通っても、意味のある出力を示そうとすると、コンパイル・リンクエラーが出て収拾できそうにない場合がある。順次作業します。

1)だけのものから4)まで進んだものと色々ある状態です。一歩でも前に進むご助言をお待ちしています。「検討事項」の欄に現状を記録するようにしています。

list

N4606 Working Draft 2016, ISO/IEC 14882, C++ standard(1) coding list
https://qiita.com/kaizen_nagoya/items/df5d62c35bd6ed1c3d43/

Compiler

clang++ --version

clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-apple-darwin17.4.0

g++-7 --version

g++-7 (Homebrew GCC 7.3.0_1) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.

(156)13.3.3.1.5 List-initialization sequence [over.ics.list]p330

p330.cpp
// N4606 Committee Draft, Standard for Programming Language C++
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf 
#define msg "p330.cpp(156)13.3.3.1.5 List-initialization sequence [over.ics.list]"
// Edited by Dr. Ogawa Kiyoshi. Compile procedure and results record.

#include <iostream>

void f(std::initializer_list<int>);
f( {} ); // OK: f(initializer_list<int>) 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
}
struct A {
A(std::initializer_list<double>); // #1
A(std::initializer_list<complex<double>>); // #2
A(std::initializer_list<std::string>); // #3
};

A a{ 1.0,2.0 }; // OK, uses #1

void g(A);
g({ "foo", "bar" }); // OK, uses #3
typedef int IA[3];
void h(const IA&);
h({ 1, 2, 3 }); // OK: identity conversion


struct A2 {
A2(std::initializer_list<int>);
};
void f(A2);
f( {'a', 'b'} ); // OK: f(A2(std::initializer_list<int>)) user-defined conversion
struct B {
B(int, double);
};
void g(B);
g( {'a', 'b'} ); // OK: g(B(int,double)) user-defined conversion
g( {1.0, 1.0} ); // error: narrowing
void f(B);
f( {'a', 'b'} ); // error: ambiguous f(A) or f(B)


struct C {
C(std::string);
};
void h(C);
h({"foo"}); // OK: h(C(std::string("foo")))
struct D {
D(A, C);
};
void i(D);
i({ {1,2}, {"bar"} }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))

struct A3 {
int m1;
double m2;
};
void f(A3);
f( {'a', 'b(} ); // OK: f(A3(int,double)) user-defined conversion
f( {1.0} ); // error: narrowing

struct A4 {
int m1;
double m2;
};
void f(const A4&);
f( {'a', 'b'} ); // OK: f(A(int,double)) user-defined conversion
f( {1.0} ); // error: narrowing
void g(const double &);
g({1}); // same conversion as int to double

void f(int);
f( {'a'} ); // OK: same conversion as char to int
f( {1.0} ); // error: narrowing

void f2(int);
f2( { } ); // OK: identity conversion


int main(){
  std::cout<< msg << std::endl;
  return EXIT_SUCCESS;
}
$ ./cppgl17.sh p330
$ clang++ p330.cpp -std=c++17 
p330.cpp:9:1: error: C++ requires a type specifier for all declarations
f( {} ); // OK: f(initializer_list<int>) identity conversion
^
p330.cpp:10:1: error: C++ requires a type specifier for all declarations
f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion
^
p330.cpp:11:1: error: C++ requires a type specifier for all declarations
f( {'a','b'} ); // OK: f(initializer_list<int>) integral promotion
^
p330.cpp:12:1: error: C++ requires a type specifier for all declarations
f( {1.0} ); // error: narrowing
^
p330.cpp:15:25: error: use of undeclared identifier 'complex'
A(std::initializer_list<complex<double>>); // #2
                        ^
p330.cpp:15:39: error: expected '(' for function-style cast or type construction
A(std::initializer_list<complex<double>>); // #2
                                ~~~~~~^
p330.cpp:15:25: error: use of undeclared identifier 'complex'
A(std::initializer_list<complex<double>>); // #2
                        ^
p330.cpp:15:39: error: expected '(' for function-style cast or type construction
A(std::initializer_list<complex<double>>); // #2
                                ~~~~~~^
p330.cpp:15:42: error: expected ')'
A(std::initializer_list<complex<double>>); // #2
                                         ^
p330.cpp:15:2: note: to match this '('
A(std::initializer_list<complex<double>>); // #2
 ^
p330.cpp:21:1: error: C++ requires a type specifier for all declarations
g({ "foo", "bar" }); // OK, uses #3
^
p330.cpp:24:1: error: C++ requires a type specifier for all declarations
h({ 1, 2, 3 }); // OK: identity conversion
^
p330.cpp:30:1: error: C++ requires a type specifier for all declarations
f( {'a', 'b'} ); // OK: f(A2(std::initializer_list<int>)) user-defined conversion
^
p330.cpp:35:1: error: C++ requires a type specifier for all declarations
g( {'a', 'b'} ); // OK: g(B(int,double)) user-defined conversion
^
p330.cpp:36:1: error: C++ requires a type specifier for all declarations
g( {1.0, 1.0} ); // error: narrowing
^
p330.cpp:38:1: error: C++ requires a type specifier for all declarations
f( {'a', 'b'} ); // error: ambiguous f(A) or f(B)
^
p330.cpp:44:1: error: C++ requires a type specifier for all declarations
h({"foo"}); // OK: h(C(std::string("foo")))
^
p330.cpp:49:1: error: C++ requires a type specifier for all declarations
i({ {1,2}, {"bar"} }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))
^
p330.cpp:56:1: error: C++ requires a type specifier for all declarations
f( {'a', 'b(} ); // OK: f(A3(int,double)) user-defined conversion
^
p330.cpp:56:10: warning: missing terminating ' character [-Winvalid-pp-token]
f( {'a', 'b(} ); // OK: f(A3(int,double)) user-defined conversion
         ^
p330.cpp:56:10: error: expected expression
fatal error: too many errors emitted, stopping now [-ferror-limit=]
1 warning and 20 errors generated.

$ g++-7 p330.cpp -std=c++17 
p330.cpp:56:10: warning: missing terminating ' character
 f( {'a', 'b(} ); // OK: f(A3(int,double)) user-defined conversion
          ^
p330.cpp:56:10: error: missing terminating ' character
 f( {'a', 'b(} ); // OK: f(A3(int,double)) user-defined conversion
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p330.cpp:9:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {} ); // OK: f(initializer_list<int>) identity conversion
  ^
p330.cpp:9:7: error: expected unqualified-id before ')' token
 f( {} ); // OK: f(initializer_list<int>) identity conversion
       ^
p330.cpp:10:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion
  ^
p330.cpp:10:12: error: expected unqualified-id before ')' token
 f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion
            ^
p330.cpp:11:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {'a','b'} ); // OK: f(initializer_list<int>) integral promotion
  ^
p330.cpp:11:14: error: expected unqualified-id before ')' token
 f( {'a','b'} ); // OK: f(initializer_list<int>) integral promotion
              ^
p330.cpp:12:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {1.0} ); // error: narrowing
  ^
p330.cpp:12:10: error: expected unqualified-id before ')' token
 f( {1.0} ); // error: narrowing
          ^
p330.cpp:15:25: error: 'complex' was not declared in this scope
 A(std::initializer_list<complex<double>>); // #2
                         ^~~~~~~
p330.cpp:15:39: error: template argument 1 is invalid
 A(std::initializer_list<complex<double>>); // #2
                                       ^~
p330.cpp:21:2: error: expected constructor, destructor, or type conversion before '(' token
 g({ "foo", "bar" }); // OK, uses #3
  ^
p330.cpp:21:19: error: expected unqualified-id before ')' token
 g({ "foo", "bar" }); // OK, uses #3
                   ^
p330.cpp:24:2: error: expected constructor, destructor, or type conversion before '(' token
 h({ 1, 2, 3 }); // OK: identity conversion
  ^
p330.cpp:24:14: error: expected unqualified-id before ')' token
 h({ 1, 2, 3 }); // OK: identity conversion
              ^
p330.cpp:30:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {'a', 'b'} ); // OK: f(A2(std::initializer_list<int>)) user-defined conversion
  ^
p330.cpp:30:15: error: expected unqualified-id before ')' token
 f( {'a', 'b'} ); // OK: f(A2(std::initializer_list<int>)) user-defined conversion
               ^
p330.cpp:35:2: error: expected constructor, destructor, or type conversion before '(' token
 g( {'a', 'b'} ); // OK: g(B(int,double)) user-defined conversion
  ^
p330.cpp:35:15: error: expected unqualified-id before ')' token
 g( {'a', 'b'} ); // OK: g(B(int,double)) user-defined conversion
               ^
p330.cpp:36:2: error: expected constructor, destructor, or type conversion before '(' token
 g( {1.0, 1.0} ); // error: narrowing
  ^
p330.cpp:36:15: error: expected unqualified-id before ')' token
 g( {1.0, 1.0} ); // error: narrowing
               ^
p330.cpp:38:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {'a', 'b'} ); // error: ambiguous f(A) or f(B)
  ^
p330.cpp:38:15: error: expected unqualified-id before ')' token
 f( {'a', 'b'} ); // error: ambiguous f(A) or f(B)
               ^
p330.cpp:44:2: error: expected constructor, destructor, or type conversion before '(' token
 h({"foo"}); // OK: h(C(std::string("foo")))
  ^
p330.cpp:44:10: error: expected unqualified-id before ')' token
 h({"foo"}); // OK: h(C(std::string("foo")))
          ^
p330.cpp:49:2: error: expected constructor, destructor, or type conversion before '(' token
 i({ {1,2}, {"bar"} }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))
  ^
p330.cpp:49:21: error: expected unqualified-id before ')' token
 i({ {1,2}, {"bar"} }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))
                     ^
p330.cpp:56:2: error: expected constructor, destructor, or type conversion before '(' token
 f( {'a', 'b(} ); // OK: f(A3(int,double)) user-defined conversion
  ^

検討事項

コンパイルエラーをなくす修正
意味のある出力

参考資料

N4606 Working Draft 2016, ISO/IEC 14882, C++ standardのコード断片をコンパイルするためにしていること
https://qiita.com/kaizen_nagoya/items/a8d7ee2f2e29e76c19c1

コンパイル用shell script C版(clangとgcc)とC++版(clang++とg++)
https://qiita.com/kaizen_nagoya/items/74220c0577a512c2d7da

Clang/Clang++(LLVM) gcc/g++(GNU) コンパイラ警告等比較
https://qiita.com/kaizen_nagoya/items/9a82b958cc3aeef0403f

Qiitaに投稿するCのStyle例(暫定)
https://qiita.com/kaizen_nagoya/items/946df1528a6a1ef2bc0d

MISRA C++ 5-0-16
https://qiita.com/kaizen_nagoya/items/7df2d4e05db724752a74

C++ Templates Part1 BASICS Chapter 3. Class Templates 3.2 Use of Class Template Stack stack1test.cpp
https://qiita.com/kaizen_nagoya/items/cd5fc49106fad5a4e9ed

ISO/IEC TS 17961:2013 C Secure Coding Rules(1) All list(to be confirmed)
https://qiita.com/kaizen_nagoya/items/54e056195c4f11b850a1

C言語(C++)に対する誤解、曲解、無理解、爽快。
https://qiita.com/kaizen_nagoya/items/3f3992c9722c1cee2e3a

C Puzzle Bookの有り難み5つ、C言語規格及びCコンパイラの特性を認識
https://qiita.com/kaizen_nagoya/items/d89a48c1536a02ecdec9

'wchar.h' file not found で困った clang++ macOS
https://qiita.com/kaizen_nagoya/items/de15cd46d657517fac11

Open POSIX Test Suiteの使い方を調べはじめました
https://qiita.com/kaizen_nagoya/items/644d5e407f5faf96e6dc

MISRA-C 2012 Referenceに掲載している文献の入手可能性を確認
https://qiita.com/kaizen_nagoya/items/96dc8b125e462d5575bb

どうやって MISRA Example Suiteをコンパイルするか
https://qiita.com/kaizen_nagoya/items/fbdbff5ff696e2ca7f00

MISRA C まとめ #include
https://qiita.com/kaizen_nagoya/items/f1a79a7cbd281607c7c9

「C++完全理解ガイド」の同意できること上位10
https://qiita.com/kaizen_nagoya/items/aa5744e0c4a8618c7671

文書履歴

0.10 初稿 2080420