C++N4606 (202)14.8.2 Template argument deduction [temp.deduct]p408


はじめに

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.

(202)14.8.2 Template argument deduction [temp.deduct]p408

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

#include <iostream>

void f(Array<dcomplex>& cv, Array<int>& ci) {
sort(cv); // calls sort(Array<dcomplex>&)
sort(ci); // calls sort(Array<int>&)
}

void g(double d) {
int i = convert<int>(d); // calls convert<int,double>(double)
int c = convert<char>(d); // calls convert<char,double>(double)
}

template <class T> void f(T t);
template <class X> void g(const X x);
template <class Z> void h(Z, Z*);
int main() {
// #1: function type is f(int), t is non const
f<int>(1);
// #2: function type is f(int), t is const
f<const int>(1);
// #3: function type is g(int), x is const
g<int>(1);
// #4: function type is g(int), x is const
g<const int>(1);
// #5: function type is h(int, const int*)
h<const int>(1,0);
  std::cout<< msg << std::endl;
  return EXIT_SUCCESS;
}
cppgl17.sh
$ ./cppgl17.sh p408
$ clang++ p408.cpp -std=c++17 
p408.cpp:8:6: error: variable has incomplete type 'void'
void f(Array<dcomplex>& cv, Array<int>& ci) {
     ^
p408.cpp:8:8: error: use of undeclared identifier 'Array'
void f(Array<dcomplex>& cv, Array<int>& ci) {
       ^
p408.cpp:8:14: error: use of undeclared identifier 'dcomplex'
void f(Array<dcomplex>& cv, Array<int>& ci) {
             ^
p408.cpp:8:25: error: use of undeclared identifier 'cv'
void f(Array<dcomplex>& cv, Array<int>& ci) {
                        ^
p408.cpp:8:29: error: use of undeclared identifier 'Array'
void f(Array<dcomplex>& cv, Array<int>& ci) {
                            ^
p408.cpp:8:38: error: expected '(' for function-style cast or type construction
void f(Array<dcomplex>& cv, Array<int>& ci) {
                                  ~~~^
p408.cpp:8:41: error: use of undeclared identifier 'ci'
void f(Array<dcomplex>& cv, Array<int>& ci) {
                                        ^
p408.cpp:8:44: error: expected ';' after top level declarator
void f(Array<dcomplex>& cv, Array<int>& ci) {
                                           ^
                                           ;
p408.cpp:23:6: error: expected '(' for function-style cast or type construction
f<int>(1);
  ~~~^
p408.cpp:25:3: error: expected expression
f<const int>(1);
  ^
10 errors generated.

$ g++-7 p408.cpp -std=c++17 
p408.cpp:8:8: error: variable or field 'f' declared void
 void f(Array<dcomplex>& cv, Array<int>& ci) {
        ^~~~~
p408.cpp:8:8: error: 'Array' was not declared in this scope
p408.cpp:8:14: error: 'dcomplex' was not declared in this scope
 void f(Array<dcomplex>& cv, Array<int>& ci) {
              ^~~~~~~~
p408.cpp:8:14: note: suggested alternative: 'double'
 void f(Array<dcomplex>& cv, Array<int>& ci) {
              ^~~~~~~~
              double
p408.cpp:8:25: error: 'cv' was not declared in this scope
 void f(Array<dcomplex>& cv, Array<int>& ci) {
                         ^~
p408.cpp:8:25: note: suggested alternative: 'gcvt'
 void f(Array<dcomplex>& cv, Array<int>& ci) {
                         ^~
                         gcvt
p408.cpp:8:29: error: 'Array' was not declared in this scope
 void f(Array<dcomplex>& cv, Array<int>& ci) {
                             ^~~~~
p408.cpp:8:35: error: expected primary-expression before 'int'
 void f(Array<dcomplex>& cv, Array<int>& ci) {
                                   ^~~
p408.cpp: In function 'void g(double)':
p408.cpp:14:9: error: 'convert' was not declared in this scope
 int i = convert<int>(d); // calls convert<int,double>(double)
         ^~~~~~~
p408.cpp:14:17: error: expected primary-expression before 'int'
 int i = convert<int>(d); // calls convert<int,double>(double)
                 ^~~
p408.cpp:15:17: error: expected primary-expression before 'char'
 int c = convert<char>(d); // calls convert<char,double>(double)
                 ^~~~

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

#include <iostream>

template <class T, class U = double>
void f(T t = 0, U u = 0);
void g() {
  f(1, 'c'); // f<int,char>(1,’c’)
  f(1); // f<int,double>(1,0)
  f(); // error: T cannot be deduced
  f<int>(); // f<int,double>(0,0)
  f<int,char>(); // f<int,char>(0,0)
}

template <class T> struct A {
  using X = typename T::X;
};
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f2(...) { }
template <class T> auto g2(typename A<T>::X) -> typename T::X;
template <class T> void g2(...) { }
void h() {
  f2<int>(0); // OK, substituting return type causes deduction to fail
  g2<int>(0); // error, substituting parameter type instantiates A<int>
}

struct X3 { };
struct Y3 {
  Y3(X3) {}
};
template <class T> auto f3(T t1, T t2) -> decltype(t1 + t2); // #1
X3 f3(Y3, Y3); // #2
X3 x1, x2;
X3 x3 = f3(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2

template <class T> int f4(T[5]);
int I = f4<int>(0);
int j = f4<void>(0); // invalid array

template <class T> int f5(typename T::B*);
int i = f5<int>(0);

template <int I> struct X6 { };
template <template <class T> class> struct Z6 { };
template <class T> void f6(typename T::Y6*) {}
template <class T> void g6(X6<T::N>*) {}
template <class T> void h6(Z6<T::template TT>*) {}
struct A6 {};
struct B6 {
  int Y6;
};
struct C6 {
  typedef int N;
};
struct D6 {
  typedef int TT;
};

int main() {
// Deduction fails in each of these cases:
  f6<A6>(0); // A does not contain a member Y
  f6<B6>(0); // The Y member of B is not a type
  g6<C6>(0); // The N member of C is not a non-type
  h6<D6>(0); // The TT member of D is not a template
  std::cout<< msg << std::endl;
  return EXIT_SUCCESS;
}

template <class T> int f7(int T::*);
int i7 = f7<int>(0);

template <class T, T> struct S8 {};
template <class T> int f8(S8<T, T()>*);
struct X8 {};
int i0 = f8<X8>(0);

template <int> int f9(int);
template <signed char> int f9(int);
int i1 = f9<1000>(0); // OK
int i2 = f9<1>(0); // ambiguous; not narrowing
$ ./cppgl17.sh p408-2
$ clang++ p408-2.cpp -std=c++17 
p408-2.cpp:13:1: error: no matching function for call to 'f'
f(); // error: T cannot be deduced
^
p408-2.cpp:9:6: note: candidate template ignored: couldn't infer template argument 'T'
void f(T t = 0, U u = 0);
     ^
p408-2.cpp:18:50: error: type 'int' cannot be used prior to '::' because it has no members
template <class T> struct A { using X = typename T::X; };
                                                 ^
p408-2.cpp:21:37: note: in instantiation of template class 'A<int>' requested here
template <class T> auto g2(typename A<T>::X) -> typename T::X;
                                    ^
p408-2.cpp:25:1: note: while substituting explicitly-specified template arguments into function template 'g2'
g2<int>(0); // error, substituting parameter type instantiates A<int>
^
p408-2.cpp:39:9: error: no matching function for call to 'f4'
int j = f4<void>(0); // invalid array
        ^~~~~~~~
p408-2.cpp:37:24: note: candidate template ignored: substitution failure [with T = void]: array has incomplete element type 'void'
template <class T> int f4(T[5]);
                       ^   ~
p408-2.cpp:42:9: error: no matching function for call to 'f5'
int i = f5<int>(0);
        ^~~~~~~
p408-2.cpp:41:24: note: candidate template ignored: substitution failure [with T = int]: type 'int' cannot be used prior to '::' because it
      has no members
template <class T> int f5(typename T::B*);
                       ^           ~
p408-2.cpp:60:1: error: no matching function for call to 'f6'
f6<A6>(0); // A does not contain a member Y
^~~~~~
p408-2.cpp:46:25: note: candidate template ignored: substitution failure [with T = A6]: no type named 'Y6' in 'A6'
template <class T> void f6(typename T::Y6*){}
                        ^              ~~
p408-2.cpp:61:1: error: no matching function for call to 'f6'
f6<B6>(0); // The Y member of B is not a type
^~~~~~
p408-2.cpp:46:25: note: candidate template ignored: substitution failure [with T = B6]: typename specifier refers to non-type member 'Y6' in
      'B6'
template <class T> void f6(typename T::Y6*){}
                        ^              ~~
p408-2.cpp:62:1: error: no matching function for call to 'g6'
g6<C6>(0); // The N member of C is not a non-type
^~~~~~
p408-2.cpp:47:25: note: candidate template ignored: substitution failure [with T = C6]: missing 'typename' prior to dependent type name
      'C6::N'
template <class T> void g6(X6<T::N>*){}
                        ^     ~
p408-2.cpp:63:1: error: no matching function for call to 'h6'
h6<D6>(0); // The TT member of D is not a template
^~~~~~
p408-2.cpp:48:25: note: candidate template ignored: substitution failure [with T = D6]: 'TT' following the 'template' keyword does not refer
      to a template
template <class T> void h6(Z6<T::template TT>*){}
                        ^                 ~~
p408-2.cpp:69:10: error: no matching function for call to 'f7'
int i7 = f7<int>(0);
         ^~~~~~~
p408-2.cpp:68:24: note: candidate template ignored: substitution failure [with T = int]: member pointer refers into non-class type 'int'
template <class T> int f7(int T::*);
                       ^      ~
p408-2.cpp:72:33: error: template argument for non-type template parameter is treated as function type 'T ()'
template <class T> int f8(S8<T, T()>*);
                                ^~~
p408-2.cpp:71:21: note: template parameter is declared here
template <class T, T> struct S8 {};
                    ^
p408-2.cpp:74:10: error: no matching function for call to 'f8'
int i0 = f8<X8>(0);
         ^~~~~~
p408-2.cpp:79:10: error: call to 'f9' is ambiguous
int i2 = f9<1>(0); // ambiguous; not narrowing
         ^~~~~
p408-2.cpp:76:20: note: candidate function [with $0 = 1]
template <int> int f9(int);
                   ^
p408-2.cpp:77:28: note: candidate function [with $0 = '\x01']
template <signed char> int f9(int);
                           ^
12 errors generated.

$ g++-7 p408-2.cpp -std=c++17 
p408-2.cpp: In function 'void g()':
p408-2.cpp:13:3: error: no matching function for call to 'f()'
 f(); // error: T cannot be deduced
   ^
p408-2.cpp:9:6: note: candidate: template<class T, class U> void f(T, U)
 void f(T t = 0, U u = 0);
      ^
p408-2.cpp:9:6: note:   template argument deduction/substitution failed:
p408-2.cpp:13:3: note:   couldn't deduce template parameter 'T'
 f(); // error: T cannot be deduced
   ^
p408-2.cpp: In instantiation of 'struct A<int>':
p408-2.cpp:21:25:   required by substitution of 'template<class T> typename T::X g2(typename A<T>::X) [with T = int]'
p408-2.cpp:25:10:   required from here
p408-2.cpp:18:54: error: 'int' is not a class, struct, or union type
 template <class T> struct A { using X = typename T::X; };
                                                      ^
p408-2.cpp: At global scope:
p408-2.cpp:42:18: error: no matching function for call to 'f5<int>(int)'
 int i = f5<int>(0);
                  ^
p408-2.cpp:41:24: note: candidate: template<class T> int f5(typename T::B*)
 template <class T> int f5(typename T::B*);
                        ^~
p408-2.cpp:41:24: note:   template argument deduction/substitution failed:
p408-2.cpp: In substitution of 'template<class T> int f5(typename T::B*) [with T = int]':
p408-2.cpp:42:18:   required from here
p408-2.cpp:41:24: error: 'int' is not a class, struct, or union type
p408-2.cpp: In function 'int main()':
p408-2.cpp:60:9: error: no matching function for call to 'f6<A6>(int)'
 f6<A6>(0); // A does not contain a member Y
         ^
p408-2.cpp:46:25: note: candidate: template<class T> void f6(typename T::Y6*)
 template <class T> void f6(typename T::Y6*){}
                         ^~
p408-2.cpp:46:25: note:   template argument deduction/substitution failed:
p408-2.cpp: In substitution of 'template<class T> void f6(typename T::Y6*) [with T = A6]':
p408-2.cpp:60:9:   required from here
p408-2.cpp:46:25: error: no type named 'Y6' in 'struct A6'
p408-2.cpp:61:9: error: no matching function for call to 'f6<B6>(int)'
 f6<B6>(0); // The Y member of B is not a type
         ^
p408-2.cpp:46:25: note: candidate: template<class T> void f6(typename T::Y6*)
 template <class T> void f6(typename T::Y6*){}
                         ^~
p408-2.cpp:46:25: note:   template argument deduction/substitution failed:
p408-2.cpp: In substitution of 'template<class T> void f6(typename T::Y6*) [with T = B6]':
p408-2.cpp:61:9:   required from here
p408-2.cpp:46:25: error: no type named 'Y6' in 'struct B6'
p408-2.cpp:62:9: error: no matching function for call to 'g6<C6>(int)'
 g6<C6>(0); // The N member of C is not a non-type
         ^
p408-2.cpp:47:25: note: candidate: template<class T> void g6(X6<T:: N>*)
 template <class T> void g6(X6<T::N>*){}
                         ^~
p408-2.cpp:47:25: note:   template argument deduction/substitution failed:
p408-2.cpp: In substitution of 'template<class T> void g6(X6<T:: N>*) [with T = C6]':
p408-2.cpp:62:9:   required from here
p408-2.cpp:47:25: error: dependent-name 'T:: N' is parsed as a non-type, but instantiation yields a type
p408-2.cpp:47:25: note: say 'typename T:: N' if a type is meant
p408-2.cpp:63:9: error: no matching function for call to 'h6<D6>(int)'
 h6<D6>(0); // The TT member of D is not a template
         ^
p408-2.cpp:48:25: note: candidate: template<class T> void h6(Z6<T::template TT>*)
 template <class T> void h6(Z6<T::template TT>*){}
                         ^~
p408-2.cpp:48:25: note:   template argument deduction/substitution failed:
p408-2.cpp: In substitution of 'template<class T> void h6(Z6<T::template TT>*) [with T = D6]':
p408-2.cpp:63:9:   required from here
p408-2.cpp:48:25: error: no class template named 'TT' in 'struct D6'
p408-2.cpp: At global scope:
p408-2.cpp:69:19: error: no matching function for call to 'f7<int>(int)'
 int i7 = f7<int>(0);
                   ^
p408-2.cpp:68:24: note: candidate: template<class T> int f7(int T::*)
 template <class T> int f7(int T::*);
                        ^~
p408-2.cpp:68:24: note:   template argument deduction/substitution failed:
p408-2.cpp: In substitution of 'template<class T> int f7(int T::*) [with T = int]':
p408-2.cpp:69:19:   required from here
p408-2.cpp:68:24: error: creating pointer to member of non-class type 'int'
p408-2.cpp:72:36: error: type/value mismatch at argument 2 in template parameter list for 'template<class T, T <anonymous> > struct S8'
 template <class T> int f8(S8<T, T()>*);
                                    ^
p408-2.cpp:72:36: note:   expected a constant of type 'T', got 'T()'
p408-2.cpp:78:20: error: call of overloaded 'f9<1000>(int)' is ambiguous
 int i1 = f9<1000>(0); // OK
                    ^
p408-2.cpp:76:20: note: candidate: int f9(int) [with int <anonymous> = 1000]
 template <int> int f9(int);
                    ^~
p408-2.cpp:77:28: note: candidate: int f9(int) [with signed char <anonymous> = -24]
 template <signed char> int f9(int);
                            ^~
p408-2.cpp:79:17: error: call of overloaded 'f9<1>(int)' is ambiguous
 int i2 = f9<1>(0); // ambiguous; not narrowing
                 ^
p408-2.cpp:76:20: note: candidate: int f9(int) [with int <anonymous> = 1]
 template <int> int f9(int);
                    ^~
p408-2.cpp:77:28: note: candidate: int f9(int) [with signed char <anonymous> = 1]
 template <signed char> int f9(int);
                            ^~

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

a.sh
#!/bin/bash
astyle -s2 -c < $1.cpp > $1s2.cpp
cat $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