C++ N4606 (98) 8.3.6 Default arguments [dcl.fct.default] p212


はじめに

N4606 Working Draft, Standard for Programming Language C++
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/#mailing2016-11
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)

g++-7 --version

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

(98) 8.3.6 Default arguments [dcl.fct.default]

p212

p212.cpp
// N4606 Committee Draft, Standard for Programming Language C++
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf 
#define msg "p212.cpp(98) 8.3.6 Default arguments [dcl.fct.default]"

#include <iostream>

void point(int = 3, int = 4);

point(1,2); point(1); point();

void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow
// a parameter with a default argument
void f(int, int);
void f(int, int = 7);
void h() {
  f(3); // OK, calls f(3, 7)
  void f(int = 1, int); // error: does not use default
  // from surrounding scope
}
void m() {
  void f(int, int); // has no defaults
  f(4); // error: wrong number of arguments
  void f(int, int = 5); // OK
  f(4); // OK, calls f(4, 5);
  void f(int, int = 5); // error: cannot redefine, even to
  // same value
}
void n() {
  f(6); // OK, calls f(6, 7)
}

int a = 1;
int f(int);
int g(int x = f(a)); // default argument: f(::a)
void h() {
  a = 2;
  {
    int a = 3;
    g(); // g(f(::a))
  }
}

class C {
  void f(int i = 3);
  void g(int i, int j = 99);
};
void C::f(int i = 3) { // error: default argument already
} // specified in class scope
  void C::g(int i = 88, int j) { // in this   translation unit,
} // C::

void f() {
  int i;
  extern void g(int x = i); // error
  extern void h(int x = sizeof(i)); // OK
  // ...
}

class A {
  void f(A* p = this) { } // error
};

int a;
int f(int a, int b = a); // error: parameter a
// used as default argument
typedef int I;
int g(float I, int b = I(2)); // error: parameter I found
int h(int a, int b = sizeof(a)); // OK, unevaluated operand
int b;
class X {
  int a;
  int mem1(int i = a); // error: non-static member a
  // used as default argument
  int mem2(int i = b); // OK; use X::b
  static int b;
};

int f(int = 0);
void h() {
  int j = f(1);
  int k = f(); // OK, means f(0)
}
int (*p1)(int) = &f;
int (*p2)() = &f; // error: type mismatch

struct A {
  virtual void f(int a = 7);
};
struct B : public A {
  void f(int a);
};
void m() {
  B* pb = new B;
  A* pa = pb;
  pa->f(); // OK, calls pa->B::f(7)
  pb->f(); // error: wrong number of arguments   for B::f()
}

int main(){
  m();
  std::cout<< msg << std::endl;
  return EXIT_SUCCESS;
}
$ ./cppgl17.sh p212
$ clang++ p212.cpp
p212.cpp:9:1: error: C++ requires a type specifier for all declarations
point(1,2); point(1); point();
^
p212.cpp:9:13: error: C++ requires a type specifier for all declarations
point(1,2); point(1); point();
            ^
p212.cpp:9:23: error: C++ requires a type specifier for all declarations
point(1,2); point(1); point();
                      ^
p212.cpp:17:22: error: missing default argument on parameter
  void f(int = 1, int); // error: does not use default
                     ^
p212.cpp:22:3: error: too few arguments to function call, expected 2, have 1; did you mean '::f'?
  f(4); // error: wrong number of arguments
  ^
  ::f
p212.cpp:14:6: note: '::f' declared here
void f(int, int = 7);
     ^
p212.cpp:25:19: error: redefinition of default argument
  void f(int, int = 5); // error: cannot redefine, even to
                  ^ ~
p212.cpp:23:19: note: previous definition is here
  void f(int, int = 5); // OK
                  ^ ~
p212.cpp:34:15: error: call to 'f' is ambiguous
int g(int x = f(a)); // default argument: f(::a)
              ^
p212.cpp:14:6: note: candidate function
void f(int, int = 7);
     ^
p212.cpp:33:5: note: candidate function
int f(int);
    ^
p212.cpp:35:6: error: redefinition of 'h'
void h() {
     ^
p212.cpp:15:6: note: previous definition is here
void h() {
     ^
p212.cpp:47:15: error: redefinition of default argument
void C::f(int i = 3) { // error: default argument already
              ^   ~
p212.cpp:44:14: note: previous definition is here
  void f(int i = 3);
             ^   ~
p212.cpp:54:25: error: default argument references local variable 'i' of enclosing function
  extern void g(int x = i); // error
                        ^
p212.cpp:55:32: error: default argument references local variable 'i' of enclosing function
  extern void h(int x = sizeof(i)); // OK
                        ~~~~~~~^~
p212.cpp:60:17: error: invalid use of 'this' outside of a non-static member function
  void f(A* p = this) { } // error
                ^
p212.cpp:63:5: error: redefinition of 'a'
int a;
    ^
p212.cpp:32:5: note: previous definition is here
int a = 1;
    ^
p212.cpp:64:22: error: default argument references parameter 'a'
int f(int a, int b = a); // error: parameter a
                     ^
p212.cpp:67:25: error: called object type 'float' is not a function or function pointer
int g(float I, int b = I(2)); // error: parameter I found
                       ~^
p212.cpp:68:29: error: default argument references parameter 'a'
int h(int a, int b = sizeof(a)); // OK, unevaluated operand
                     ~~~~~~~^~
p212.cpp:72:20: error: invalid use of non-static data member 'a'
  int mem1(int i = a); // error: non-static member a
                   ^
p212.cpp:80:11: error: call to 'f' is ambiguous
  int j = f(1);
          ^
p212.cpp:14:6: note: candidate function
void f(int, int = 7);
     ^
p212.cpp:78:5: note: candidate function
int f(int = 0);
    ^
p212.cpp:81:11: error: call to 'f' is ambiguous
  int k = f(); // OK, means f(0)
          ^
p212.cpp:52:6: note: candidate function
void f() {
     ^
p212.cpp:78:5: note: candidate function
int f(int = 0);
    ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.

$ g++-7 p212.cpp
p212.cpp:9:6: error: expected constructor, destructor, or type conversion before '(' token
 point(1,2); point(1); point();
      ^
p212.cpp:9:18: error: expected constructor, destructor, or type conversion before '(' token
 point(1,2); point(1); point();
                  ^
p212.cpp:9:30: error: expected constructor, destructor, or type conversion before ';' token
 point(1,2); point(1); point();
                              ^
p212.cpp: In function 'void h()':
p212.cpp:17:8: error: default argument missing for parameter 2 of 'void f(int, int)'
   void f(int = 1, int); // error: does not use default
        ^
p212.cpp: In function 'void m()':
p212.cpp:22:6: error: too few arguments to function 'void f(int, int)'
   f(4); // error: wrong number of arguments
      ^
p212.cpp:21:8: note: declared here
   void f(int, int); // has no defaults
        ^
p212.cpp:25:22: error: default argument given for parameter 2 of 'void f(int, int)' [-fpermissive]
   void f(int, int = 5); // error: cannot redefine, even to
                      ^
p212.cpp:23:8: note: previous specification in 'void f(int, int)' here
   void f(int, int = 5); // OK
        ^
p212.cpp: At global scope:
p212.cpp:34:18: error: call of overloaded 'f(int&)' is ambiguous
 int g(int x = f(a)); // default argument: f(::a)
                  ^
p212.cpp:14:6: note: candidate: void f(int, int)
 void f(int, int = 7);
      ^
p212.cpp:33:5: note: candidate: int f(int)
 int f(int);
     ^
p212.cpp: In function 'void h()':
p212.cpp:35:6: error: redefinition of 'void h()'
 void h() {
      ^
p212.cpp:15:6: note: 'void h()' previously defined here
 void h() {
      ^
p212.cpp:39:7: error: call of overloaded 'g()' is ambiguous
     g(); // g(f(::a))
       ^
p212.cpp:11:6: note: candidate: void g(int, ...)
 void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow
      ^
p212.cpp:34:5: note: candidate: int g(int)
 int g(int x = f(a)); // default argument: f(::a)
     ^
p212.cpp: At global scope:
p212.cpp:47:20: error: default argument given for parameter 1 of 'void C::f(int)' [-fpermissive]
 void C::f(int i = 3) { // error: default argument already
                    ^
p212.cpp:44:8: note: previous specification in 'void C::f(int)' here
   void f(int i = 3);
        ^
p212.cpp: In function 'void f()':
p212.cpp:54:25: error: local variable 'i' may not appear in this context
   extern void g(int x = i); // error
                         ^
p212.cpp:55:32: error: local variable 'i' may not appear in this context
   extern void h(int x = sizeof(i)); // OK
                                ^
p212.cpp: At global scope:
p212.cpp:60:17: error: 'this' may not be used in this context
   void f(A* p = this) { } // error
                 ^~~~
p212.cpp:63:5: error: redefinition of 'int a'
 int a;
     ^
p212.cpp:32:5: note: 'int a' previously defined here
 int a = 1;
     ^
p212.cpp:64:22: error: local variable 'a' may not appear in this context
 int f(int a, int b = a); // error: parameter a
                      ^
p212.cpp:64:5: error: ambiguating new declaration of 'int f(int, int)'
 int f(int a, int b = a); // error: parameter a
     ^
p212.cpp:14:6: note: old declaration 'void f(int, int)'
 void f(int, int = 7);
      ^
p212.cpp:67:24: error: local variable 'I' may not appear in this context
 int g(float I, int b = I(2)); // error: parameter I found
                        ^
p212.cpp:68:29: error: local variable 'a' may not appear in this context
 int h(int a, int b = sizeof(a)); // OK, unevaluated operand
                             ^
p212.cpp:72:20: error: invalid use of non-static data member 'X::a'
   int mem1(int i = a); // error: non-static member a
                    ^
p212.cpp:71:7: note: declared here
   int a;
       ^
p212.cpp: In function 'void h()':
p212.cpp:79:6: error: redefinition of 'void h()'
 void h() {
      ^
p212.cpp:15:6: note: 'void h()' previously defined here
 void h() {
      ^
p212.cpp:80:14: error: call of overloaded 'f(int)' is ambiguous
   int j = f(1);
              ^
p212.cpp:14:6: note: candidate: void f(int, int)
 void f(int, int = 7);
      ^
p212.cpp:78:5: note: candidate: int f(int)
 int f(int = 0);
     ^
p212.cpp:81:13: error: call of overloaded 'f()' is ambiguous
   int k = f(); // OK, means f(0)
             ^
p212.cpp:78:5: note: candidate: int f(int)
 int f(int = 0);
     ^
p212.cpp:52:6: note: candidate: void f()
 void f() {
      ^
p212.cpp: At global scope:
p212.cpp:84:16: error: no matches converting function 'f' to type 'int (*)()'
 int (*p2)() = &f; // error: type mismatch
                ^
p212.cpp:52:6: note: candidates are: void f()
 void f() {
      ^
p212.cpp:78:5: note:                 int f(int)
 int f(int = 0);
     ^
p212.cpp:14:6: note:                 void f(int, int)
 void f(int, int = 7);
      ^
p212.cpp:86:8: error: redefinition of 'struct A'
 struct A {
        ^
p212.cpp:59:7: note: previous definition of 'struct A'
 class A {
       ^
p212.cpp: In function 'void m()':
p212.cpp:92:6: error: redefinition of 'void m()'
 void m() {
      ^
p212.cpp:20:6: note: 'void m()' previously defined here
 void m() {
      ^
p212.cpp:95:9: error: 'void A::f(A*)' is private within this context
   pa->f(); // OK, calls pa->B::f(7)
         ^
p212.cpp:60:8: note: declared private here
   void f(A* p = this) { } // error
        ^
p212.cpp:95:9: error: call to 'void A::f(A*)' uses the default argument for parameter 1, which is not yet defined
   pa->f(); // OK, calls pa->B::f(7)
         ^
p212.cpp:96:9: error: no matching function for call to 'B::f()'
   pb->f(); // error: wrong number of arguments   for B::f()
         ^
p212.cpp:90:8: note: candidate: void B::f(int)
   void f(int a);
        ^
p212.cpp:90:8: note:   candidate expects 1 argument, 0 provided

検討事項

今回、たまたまg++が実行時エラーになったのかどうかの確認。
g++の実行時エラーを修正する方法。

参考資料

コンパイル用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++完全理解ガイド」の同意できること上位7
https://qiita.com/kaizen_nagoya/items/aa5744e0c4a8618c7671

文書履歴

0.10 初稿 2080417