C++N4606(203)14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]p412


はじめに

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.

(203)14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]p412

p412.cpp
// N4606 Committee Draft, Standard for Programming Language C++
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
#define msg "(203)14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]p412.cpp"
// Edited by Dr. Ogawa Kiyoshi. Compile procedure and results record.

#include <iostream>

template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int, N deduced to 3
template<class T> void j(T const(&)[3]);
j({42}); // T deduced to int, array bound not considered
struct Aggr {
  int i;
  int j;
};
template<int N> void k(Aggr const(&)[N]);
k({1,2,3}); // error: deduction fails, no conversion from int to Aggr
k({{1},{2},{3}}); // OK, N deduced to 3
template<int M, int N> void m(int const(&)[M][N]);
m({{1,2},{3,4}}); // M and N both deduced to 2
template<class T, int N> void n(T const(&)[N], T);
n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3

template<class ... Types> void f2(Types& ...);
template<class T1, class ... Types> void g2(T1, Types ...);
template<class T1, class ... Types> void g1(Types ..., T1);
void h2(int x, float& y) {
  const int z = x;
  f2(x, y, z); // Types is deduced to int, float, const int
  g2(x, y, z); // T1 is deduced to int; Types is deduced to float, int
  g1(x, y, z); // error: Types is not deduced
  g1<int, int, int>(x, y, z); // OK, no deduction occurs
}

template <class T> int f3(T&& heisenreference);
template <class T> int g3(const T&&);
int i;
int n1 = f3(i); // calls f<int&>(int&)
int n2 = f3(0); // calls f<int>(int&&)
int n3 = g3(i); // error: would call g<int>(const int&&), which
// would bind an rvalue reference to an lvalue

// Only one function of an overload set matches the call so the function
// parameter is a deduced context.
template <class T> int f4(T (*p)(T));
int g4(int);
int g4(char);
int i4 = f4(g4); // calls f4(int (*)(int))

// Ambiguous deduction causes the second function parameter to be a
// non-deduced context.
template <class T> int f5(T, T (*p)(T));
int g5(int);
char g5(char);
int i5 = f5(1, g5); // calls f5(int, int (*)(int))

// The overload set contains a template, causing the second function
// parameter to be a non-deduced context.
template <class T> int f6(T, T (*p)(T));
char g6(char);
template <class T> T g6(T);
int i6 = f6(1, g6); // calls f6(int, int (*)(int))

template <class T> struct Z7 {
  typedef typename T::x xx;
};
template <class T> typename Z7<T>::xx f7(void *, T); // #1
template <class T> void f7(int, T); // #2
struct A7 {} a;
int main() {
  f7(1, a); // OK, deduction fails for #1 because there is no conversion from int to void*
  std::cout<< msg << std::endl;
  return EXIT_SUCCESS;
}
$ ./cppgl17.sh p412
$ clang++ p412.cpp -std=c++17 
p412.cpp:9:1: error: C++ requires a type specifier for all declarations
f({1,2,3}); // T deduced to int
^
p412.cpp:10:1: error: C++ requires a type specifier for all declarations
f({1,"asdf"}); // error: T deduced to both int and const char*
^
p412.cpp:12:1: error: C++ requires a type specifier for all declarations
g({1,2,3}); // error: no argument deduced for T
^
p412.cpp:14:1: error: C++ requires a type specifier for all declarations
h({1,2,3}); // T deduced to int, N deduced to 3
^
p412.cpp:16:1: error: C++ requires a type specifier for all declarations
j({42}); // T deduced to int, array bound not considered
^
p412.cpp:19:1: error: C++ requires a type specifier for all declarations
k({1,2,3}); // error: deduction fails, no conversion from int to Aggr
^
p412.cpp:20:1: error: C++ requires a type specifier for all declarations
k({{1},{2},{3}}); // OK, N deduced to 3
^
p412.cpp:22:1: error: C++ requires a type specifier for all declarations
m({{1,2},{3,4}}); // M and N both deduced to 2
^
p412.cpp:24:1: error: C++ requires a type specifier for all declarations
n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
^
p412.cpp:33:1: error: no matching function for call to 'g1'
g1(x, y, z); // error: Types is not deduced
^~
p412.cpp:28:42: note: candidate function not viable: requires 1 argument, but 3 were provided
template<class T1, class ... Types> void g1(Types ..., T1);
                                         ^
p412.cpp:42:10: error: no matching function for call to 'g3'
int n3 = g3(i); // error: would call g<int>(const int&&), which
         ^~
p412.cpp:38:24: note: candidate function [with T = int] not viable: no known conversion from 'int' to 'const int &&' for 1st argument
template <class T> int g3(const T&&);
                       ^
11 errors generated.

$ g++-7 p412.cpp -std=c++17 
p412.cpp:9:2: error: expected constructor, destructor, or type conversion before '(' token
 f({1,2,3}); // T deduced to int
  ^
p412.cpp:9:10: error: expected unqualified-id before ')' token
 f({1,2,3}); // T deduced to int
          ^
p412.cpp:10:2: error: expected constructor, destructor, or type conversion before '(' token
 f({1,"asdf"}); // error: T deduced to both int and const char*
  ^
p412.cpp:10:13: error: expected unqualified-id before ')' token
 f({1,"asdf"}); // error: T deduced to both int and const char*
             ^
p412.cpp:12:2: error: expected constructor, destructor, or type conversion before '(' token
 g({1,2,3}); // error: no argument deduced for T
  ^
p412.cpp:12:10: error: expected unqualified-id before ')' token
 g({1,2,3}); // error: no argument deduced for T
          ^
p412.cpp:14:2: error: expected constructor, destructor, or type conversion before '(' token
 h({1,2,3}); // T deduced to int, N deduced to 3
  ^
p412.cpp:14:10: error: expected unqualified-id before ')' token
 h({1,2,3}); // T deduced to int, N deduced to 3
          ^
p412.cpp:16:2: error: expected constructor, destructor, or type conversion before '(' token
 j({42}); // T deduced to int, array bound not considered
  ^
p412.cpp:16:7: error: expected unqualified-id before ')' token
 j({42}); // T deduced to int, array bound not considered
       ^
p412.cpp:19:2: error: expected constructor, destructor, or type conversion before '(' token
 k({1,2,3}); // error: deduction fails, no conversion from int to Aggr
  ^
p412.cpp:19:10: error: expected unqualified-id before ')' token
 k({1,2,3}); // error: deduction fails, no conversion from int to Aggr
          ^
p412.cpp:20:2: error: expected constructor, destructor, or type conversion before '(' token
 k({{1},{2},{3}}); // OK, N deduced to 3
  ^
p412.cpp:20:16: error: expected unqualified-id before ')' token
 k({{1},{2},{3}}); // OK, N deduced to 3
                ^
p412.cpp:22:2: error: expected constructor, destructor, or type conversion before '(' token
 m({{1,2},{3,4}}); // M and N both deduced to 2
  ^
p412.cpp:22:16: error: expected unqualified-id before ')' token
 m({{1,2},{3,4}}); // M and N both deduced to 2
                ^
p412.cpp:24:2: error: expected constructor, destructor, or type conversion before '(' token
 n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
  ^
p412.cpp:24:16: error: expected unqualified-id before ',' token
 n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
                ^
p412.cpp:24:23: error: expected constructor, destructor, or type conversion before ')' token
 n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
                       ^
p412.cpp: In function 'void h2(int, float&)':
p412.cpp:33:11: error: no matching function for call to 'g1(int&, float&, const int&)'
 g1(x, y, z); // error: Types is not deduced
           ^
p412.cpp:28:42: note: candidate: template<class T1, class ... Types> void g1(Types ..., T1)
 template<class T1, class ... Types> void g1(Types ..., T1);
                                          ^~
p412.cpp:28:42: note:   template argument deduction/substitution failed:
p412.cpp:33:11: note:   candidate expects 1 argument, 3 provided
 g1(x, y, z); // error: Types is not deduced
           ^
p412.cpp: At global scope:
p412.cpp:42:14: error: cannot bind rvalue reference of type 'const int&&' to lvalue of type 'int'
 int n3 = g3(i); // error: would call g<int>(const int&&), which
              ^
p412.cpp:38:24: note:   initializing argument 1 of 'int g3(const T&&) [with T = int]'
 template <class T> int g3(const T&&);
                        ^~


タブを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