C++N4606(166)14.1 Template parameters [temp.param]p347


はじめに

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)
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.

(166)14.1 Template parameters [temp.param]p347

p347.cpp
// N4606 Committee Draft, Standard for Programming Language C++
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
#define msg "p347.cpp(166)14.1 Template parameters [temp.param]"
// Edited by Dr. Ogawa Kiyoshi. Compile procedure and results record.

#include <iostream>

class T { /* ... */
};
int i;
template<class T, T i> void f(T t) {
  T t1 = i; // template-parameters T and i
  ::T t2 = ::i; // global namespace members T and i
}

template<class T> class myarray { /* ... */
};
template<class K, class V, template<class T> class C = myarray>
class Map {
  C<K> key;
  C<V> value;
};

template<const X& x, int i> void f() {
  i++; // error: change of template-parameter value
  &x; // OK
  &i; // error: address of non-reference template-parameter
  int& ri = i; // error: non-const reference bound to temporary
  const int& cri = i; // OK: const reference bound to temporary
}

template<double d> class X; // error
template<double* pd> class Y; // OK
template<double& rd> class Z; // OK

template<int* a> struct R { /* ... */
};
template<int b[5]> struct S { /* ... */
};
int p;
R<&p> w; // OK
S<&p> x; // OK due to parameter adjustment
int v[5];
R<v> y; // OK due to implicit argument conversion
S<v> z; // OK due to both adjustment and conversion

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;

template<class T1 = int, class T2 = int> class A;

template<class T1 = int, class T2> class B; // error
// U can be neither deduced from the parameter-type-list nor specified
template<class... T, class... U> void f() { } // error
template<class... T, class U> void g() { } // error

template<class T = int> class X;
template<class T = int> class X { /*... */
}; // error

template<int i = 3 > 4 > // syntax error
class X { /* ... */
};
template<int i = (3 > 4) > // OK
class Y { /* ... */
};

template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
  inline void f();
  inline void g();
};
template <template <class TT> class T> void A<T>::f() {
  T<> t; // error - TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
  T<> t; // OK - T<char>
}

template <class... Types> class Tuple; // Types is a template type parameter pack
// but not a pack expansion
template <class T, int... Dims> struct multi_array; // Dims is a non-type template parameter pack
// but not a pack expansion
template<class... T> struct value_holder {
  template<T... Values> struct apply { }; // Values is a non-type template parameter pack
// and a pack expansion
};
template<class... T, T... Values> struct static_array;// error: Values expands template type parameter
// pack T within the same template parameter list

int main() {
  std::cout<< msg << std::endl;
  return EXIT_SUCCESS;
}
$ ./cppgl17.sh p347
$ clang++ p347.cpp
p347.cpp:13:7: error: no viable conversion from 'int' to '::T'
  ::T t2 = ::i; // global namespace members T and i
      ^    ~~~
p347.cpp:8:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const T &' for 1st
      argument
class T { /* ... */
      ^
p347.cpp:8:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'T &&' for 1st
      argument
class T { /* ... */
      ^
p347.cpp:24:16: error: unknown type name 'X'
template<const X& x, int i> void f() {
               ^
p347.cpp:25:4: error: expression is not assignable
  i++; // error: change of template-parameter value
  ~^
p347.cpp:27:3: error: cannot take the address of an rvalue of type 'int'
  &i; // error: address of non-reference template-parameter
  ^~
p347.cpp:28:8: error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
  int& ri = i; // error: non-const reference bound to temporary
       ^    ~
p347.cpp:26:3: warning: expression result unused [-Wunused-value]
  &x; // OK
  ^~
p347.cpp:32:17: error: a non-type template parameter cannot have type 'double'
template<double d> class X; // error
                ^
p347.cpp:50:21: error: template parameter redefines default argument
template<class T1 = int, class T2 = int> class A;
                    ^
p347.cpp:48:21: note: previous default template argument defined here
template<class T1 = int, class T2> class A;
                    ^
p347.cpp:50:37: error: template parameter redefines default argument
template<class T1 = int, class T2 = int> class A;
                                    ^
p347.cpp:47:31: note: previous default template argument defined here
template<class T1, class T2 = int> class A;
                              ^
p347.cpp:52:32: error: template parameter missing a default argument
template<class T1 = int, class T2> class B; // error
                               ^
p347.cpp:52:21: note: previous default template argument defined here
template<class T1 = int, class T2> class B; // error
                    ^
p347.cpp:57:16: error: template parameter has a different kind in template redeclaration
template<class T = int> class X;
               ^
p347.cpp:32:17: note: previous template declaration is here
template<double d> class X; // error
                ^
p347.cpp:58:16: error: template parameter has a different kind in template redeclaration
template<class T = int> class X { /*... */
               ^
p347.cpp:32:17: note: previous template declaration is here
template<double d> class X; // error
                ^
p347.cpp:61:22: error: expected unqualified-id
template<int i = 3 > 4 > // syntax error
                     ^
p347.cpp:64:14: error: template non-type parameter has a different type 'int' in template redeclaration
template<int i = (3 > 4) > // OK
             ^
p347.cpp:33:18: note: previous non-type template parameter with type 'double *' is here
template<double* pd> class Y; // OK
                 ^
p347.cpp:68:1: error: too few template parameters in template redeclaration
template <class T = float> struct B {};
^~~~~~~~~~~~~~~~~~~~~~~~~~
p347.cpp:52:1: note: previous template declaration is here
template<class T1 = int, class T2> class B; // error
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p347.cpp:69:1: error: too few template parameters in template redeclaration
template <template <class TT = float> class T> struct A {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p347.cpp:50:1: note: previous template declaration is here
template<class T1 = int, class T2 = int> class A;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p347.cpp:73:47: error: use of template template parameter 'T' requires template arguments
template <template <class TT> class T> void A<T>::f() {
                                              ^
p347.cpp:73:37: note: template is declared here
template <template <class TT> class T> void A<T>::f() {
                                    ^
p347.cpp:88:19: error: template parameter pack must be the last template parameter
template<class... T, T... Values> struct static_array;// error: Values expands template type parameter
                  ^
1 warning and 17 errors generated.

$ g++-7 p347.cpp
p347.cpp:24:16: error: 'X' does not name a type
 template<const X& x, int i> void f() {
                ^
p347.cpp:32:1: error: expected '>' before 'template'
 template<double d> class X; // error
 ^~~~~~~~
p347.cpp:32:27: error: expected unqualified-id before ';' token
 template<double d> class X; // error
                           ^
p347.cpp:50:48: error: redefinition of default argument for 'class T1'
 template<class T1 = int, class T2 = int> class A;
                                                ^
p347.cpp:47:10: note: original definition appeared here
 template<class T1, class T2 = int> class A;
          ^~~~~
p347.cpp:52:42: error: no default argument for 'T2'
 template<class T1 = int, class T2> class B; // error
                                          ^
p347.cpp:58:31: error: redefinition of default argument for 'class T'
 template<class T = int> class X { /*... */
                               ^
p347.cpp:57:10: note: original definition appeared here
 template<class T = int> class X;
          ^~~~~
p347.cpp:61:22: error: expected unqualified-id before numeric constant
 template<int i = 3 > 4 > // syntax error
                      ^
p347.cpp:33:18: error: template parameter 'double* pd'
 template<double* pd> class Y; // OK
                  ^~
p347.cpp:65:7: error: redeclared here as 'int i'
 class Y { /* ... */
       ^
p347.cpp:68:35: error: redeclared with 1 template parameter
 template <class T = float> struct B {};
                                   ^
p347.cpp:52:42: note: previous declaration 'template<class T1, class T2> class B' used 2 template parameters
 template<class T1 = int, class T2> class B; // error
                                          ^
p347.cpp:69:55: error: redeclared with 1 template parameter
 template <template <class TT = float> class T> struct A {
                                                       ^
p347.cpp:47:42: note: previous declaration 'template<class T1, class T2> class A' used 2 template parameters
 template<class T1, class T2 = int> class A;
                                          ^
p347.cpp:73:48: error: type/value mismatch at argument 1 in template parameter list for 'template<class T1, class T2> class A'
 template <template <class TT> class T> void A<T>::f() {
                                                ^
p347.cpp:73:48: note:   expected a type, got 'T'
p347.cpp: In function 'void f()':
p347.cpp:74:5: error: wrong number of template arguments (0, should be 1)
   T<> t; // error - TT has no default template argument
     ^
p347.cpp:73:37: note: provided for 'template<class TT> class T'
 template <template <class TT> class T> void A<T>::f() {
                                     ^
p347.cpp: At global scope:
p347.cpp:76:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class T1, class T2> class A'
 template <template <class TT = char> class T> void A<T>::g() {
                                                       ^
p347.cpp:76:55: note:   expected a type, got 'T'
p347.cpp:88:10: error: parameter pack 'T' must be at the end of the template parameter list
 template<class... T, T... Values> struct static_array;// error: Values expands template type parameter
          ^~~~~

タブを2つの空白に変換しているスクリプトは下記。

a.sh
#!/bin/bash
astyle -s2 -c < $1.cpp > $1s2.cpp

検討事項

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

参考資料

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