SlideShare a Scribd company logo
Effective Modern C++
勉強会#7
Item 27
刈谷 満(@kariya_mitsuru)
2015/6/17
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
ユニバーサルリファレンスを伴う
オーバーロードの代替案に
慣れ親しもう
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
Item 26 で見たように、ユニバーサルリ
ファレンスを伴うオーバーロードはヤバい
でも、オーバーロード便利
(ただし、思った通りに動いてくれれば)
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
こんな代替案がある
1. オーバーロードを諦める
2. const T& で渡す
3. 値で渡す
4. タグディスパッチを使う
5. ユニバーサルリファレンスをとるテンプレートに
制約を設ける
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
1.オーバーロードを諦める
そのまんま
オーバーロードするから訳が分からなくなる
⇓
オーバーロードしなきゃいんじゃね?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
void logAndAdd(T&& name);
void logAndAdd(int idx);
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
void logAndAdd(T&& name);
void logAndAdd(int idx);
こうじゃ
template<typename T>
void logAndAddName(T&& name);
void logAndAddNameIdx(int idx);
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
void logAndAdd(T&& name);
void logAndAdd(int idx);
こうじゃ
template<typename T>
void logAndAddName(T&& name);
void logAndAddNameIdx(int idx);
全て解決!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
欠点
コンストラクタには無力
(コンストラクタには名前が無い)
本には名前固定って書いてあるけど、名前無いっすよ…
§12[class.ctor]/p.1 "Constructors do not have names."
てか、やっぱオーバーロード使いたくね?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
2.const T& で渡す
そのまんま
ユニバーサルリファレンス使うから訳がわからなくなる
⇓
ユニバーサルリファレンス使わなきゃいんじゃね?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
void logAndAdd(T&& name);
void logAndAdd(int idx);
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
void logAndAdd(T&& name);
void logAndAdd(int idx);
こうじゃ
void logAndAdd(const std::string&
name);
void logAndAdd(int idx);
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
void logAndAdd(T&& name);
void logAndAdd(int idx);
こうじゃ
void logAndAdd(const std::string&
name);
void logAndAdd(int idx);
全て解決!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
欠点
ユニバーサルリファレンス使う方法ほど
効率的じゃない
(でもシンプルさは魅力的)
てか、やっぱユニバーサルリファレンス
使いたくね?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
3.値で渡す
そのまんま
…え?効率は?
実はわりと効率がいい(場合も多い)
けど、詳細は Item 41 のお楽しみ
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
explicit Person(T&& n)
: name(std::forward<T>(n)) {}
explicit Person(int idx)
: name(nameFromIdx(idx)) {}
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
explicit Person(T&& n)
: name(std::forward<T>(n)) {}
explicit Person(int idx)
: name(nameFromIdx(idx)) {}
こうじゃ
explicit Person(std::string n)
: name(std::move(n)) {}
explicit Perosn(int idx)
: name(nameFromIdx(idx)) {}
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これを
template<typename T>
explicit Person(T&& n)
: name(std::forward<T>(n)) {}
explicit Person(int idx)
: name(nameFromIdx(idx)) {}
こうじゃ
explicit Person(std::string n)
: name(std::move(n)) {}
explicit Perosn(int idx)
: name(nameFromIdx(idx)) {}
全て解決!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
欠点
この例ならわりと効率いいけど、
ユニバーサルリファレンスほどじゃないし、
ムーブが効率悪い場合には使えない。(std::array とか…)
Item 41 を知らない人が見ると、「効率悪い!」と言われて、
最悪直される(※ 個人の感想です)
0 はともかく、NULL を渡すと int バージョン呼ばれる。
(けど、これに限らないし、Item 8 読め)
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
4.タグディスパッチを使う
やっぱ完全転送したい!!!
⇓
みんな大好き、タグディスパッチ
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
わ
あ
い
タ
グ
デ
ィ
ス
パ
ッ
チ
め
う
め
う
タ
グ
デ
ィ
ス
パ
ッ
チ
大
好
き
め
う
©芽兎めう
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
ユニバーサルリファレンスの問題点
あらゆる引数に完全一致する
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
引
数
が
一
つ
し
か
な
い
と
錯
覚
し
て
い
た
?
©藍染惣右介
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
解決策
ユニバーサルリファレンス以外
の引数で、オーバーロード解決
を制御すれば良い
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
元のコード
std::multiset<std::string> names;
template<typename T>
void logAndAdd(T&& name)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std::forward<T>(name));
}
これに、int を取るオーバーロードを追加したい
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
logAndAdd のオーバーロードを追加するんじゃなくて、
logAndAdd 内で実際に処理する関数
logAndAddImpl に処理を委譲する
⇓
この際、T が int の場合用と
そうじゃない場合用の関数を作って
それらの関数に追加の引数を追加して、
それらの型(タグ)が完璧に異なれば良い
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
クライアントが呼び出す関数
template<typename T>
void logAndAdd(T&& name)
{
logAndAddImpl(name,
型①か型②);
}
実際に処理する関数
void logAndAddImpl(T&& name,
型①)
{
int 以外の時の処理がここに
}
void logAndAddImpl(int idx,
型②)
{
int の時の処理がここに
}T が int の以外時は「型①」
T が int の時は「型②」
つまり、こんな感じにすれば良い
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
クライアントが呼び出す関数
template<typename T>
void logAndAdd(T&& name)
{
logAndAddImpl(name,
型①か型②);
}
実際に処理する関数
void logAndAddImpl(T&& name,
型①)
{
int 以外の時の処理がここに
}
void logAndAddImpl(int idx,
型②)
{
int の時の処理がここに
}T が int の以外時は「型①」
T が int の時は「型②」
つまり、こんな感じにすれば良い
で?
「型①か型②」って?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これが「型①か型②」だ!!!
template<typename T>
void logAndAdd(T&& name)
{
logAndAddImpl(std::forward<T>(name),
std::is_integral<T>());
}
引数だから、() を付
けてオブジェクト生成
T が int 以外の時は「std::false_type」から派生
T が int の時は「std::true_type」から派生
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これが「型①か型②」だ!!!
template<typename T>
void logAndAdd(T&& name)
{
logAndAddImpl(std::forward<T>(name),
std::is_integral<T>());
}
引数だから、() を付
けてオブジェクト生成
T が int 以外の時は「std::false_type」から派生
T が int の時は「std::true_type」から派生
でもちょっと
うまくない…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
int i = 10;
…
logAndAdd(i);
template<typename T>
void logAndAdd(T&& name)
{
logAndAddImpl(
std::forward<T>(name),
std::is_integral<T>());
}
うまくない理由
こんな感じで呼び出すと…
T が int& になっちゃう
⇒参照型は整数型じゃないから、
std::false_typeになっちゃう
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
これが正しい「型①か型②」だ!!!
template<typename T>
void logAndAdd(T&& name)
{
logAndAddImpl(
std::forward<T>(name),
std::is_integral<typename std::remove_reference<T>::type>());
}
T が int っぽくない時は「std::false_type」
T が int っぽい時は「std::true_type」
T から「参照」を消す
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
ちな、処理本体側はこんな感じ
// int 以外用の関数
template<typename T>
void logAndAddImpl(T&& name, std::false_type)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std::forward<T>(name));
}
std::string nameFromIdx(int idx);
// int 用の関数
void logAndAddImpl(int idx, std::true_type)
{
logAndAdd(nameFromIdx(idx));
}
オーバーロード解決の
ためだけにあるから、
パラメータ名は
付けてない
オーバーロード解決の
ためだけにあるから、
パラメータ名は
付けてない
idx から名前に
変換したら、
再度 logAndAdd を
呼び出す
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
ちな、処理本体側はこんな感じ
// int 以外用の関数
template<typename T>
void logAndAddImpl(T&& name, std::false_type)
{
auto now = std::chrono::system_clock::now();
log(now, "logAndAdd");
names.emplace(std::forward<T>(name));
}
std::string nameFromIdx(int idx);
// int 用の関数
void logAndAddImpl(int idx, std::true_type)
{
logAndAdd(nameFromIdx(idx));
}
オーバーロード解決の
ためだけにあるから、
パラメータ名は
付けてない
オーバーロード解決の
ためだけにあるから、
パラメータ名は
付けてない
idx から名前に
変換したら、
再度 logAndAdd を
呼び出す
賢いコンパイラなら、
最後のパラメータ使ってないから
消してくれるかも…
こうすれば、ログ出力コード
二重にメンテしなくて済む…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
タグディスパッチSUGEEEE!!!!
タグディスパッチのこと
もっと知りたい!!!
でも EMC++ にはそこまで書かれてない…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
そんなあなたに C++テンプレートテクニック 第2版
あのえぴさんと
アキラさんが
書いてるぞ!!!
C++11
完全対応!!!
電子書籍版も
あるぞ!!!
ちょっと読みづらいけど…
タグディスパッチ
だけじゃなくて
テンプレート
全般!!!
まだ全部理解できてないけど…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
タグディスパッチいいよ、タグディスパッチ
もう何もかもタグディスパッチでよくね?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
欠点
コンストラクタには無力
(またっすか…)
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
例のダメなクラス
class Person {
public:
template<typename T>
explicit Person(T&& n)
: name(std::forward<Person&>(n)) {}
explicit Person(int idx);
Person(const Person& rhs);
Person(Person&& rhs);
…
};
完全転送
コンストラクタ
int
コンストラクタ コピー
コンストラクタ
ムーブ
コンストラクタ
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
例のダメなクラス
class Person {
public:
template<typename T>
explicit Person(T&& n)
: name(std::forward<Person&>(n)) {}
explicit Person(int idx);
Person(const Person& rhs);
Person(Person&& rhs);
…
};
Person p("Nancy");
auto cloneOfP(p);
全部完全転送…
上はいいけど、下に対して
コピーコンストラクタが
呼ばれない…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
5.ユニバーサルリファレンスをとるテンプレートに制約を設ける
そのまんま
ユニバーサルリファレンスを取る関数が
呼ばれて欲しくない時まで呼ばれちゃう
⇓
関数を呼ばれて欲しい時だけ
有効にすればいんじゃね?
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
「関数を呼ばれて欲しい時だけ有効に」?
そのためのメタ関数が type_traits に!
std::enable_if
SFINAE と呼ばれる
機構を使ってる
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
使い方はこんな感じ
class Person {
public:
template<typename T,
typename = typename std::enable_if<condition>::type>
explicit Person(T&& n);
…
}; この condition の部分に、このコンストラク
タを使っても良い条件式を書く。
ただし、コンパイル時定数のみ!!
関数テンプレートのデフォルトテンプレート引数
(C++11の新機能!)を enable_if にする
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
では、今回の場合、どんな時に呼ばれて欲しいのか?
⇓
T が Person じゃない時
T が Person の場合、コピーコンストラクタや
ムーブコンストラクタが呼ばれて欲しいから
そんな時も type_traits
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
こんな式
!std::is_same<Person, T>::value
先頭の!に注意 Person と T が
同じ型の時 true
型じゃなくて
bool 値が欲しいから
::value
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<
typename T,
typename = typename std::enable_if<
!std::is_same<Person, T>::value
>::type
>
explicit Person(T&& n);
Person(const Person&);
Person(Person&&);
…
};
ダメでした…
Person p("Nancy");
auto cloneOfP(p);
T は
const char(&)[6]
T は
Person&
p は左辺値だから
T が左辺値参照に…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
T と Person を比較する時には、以下の2点を無視したい
• 参照かどうか
引数の型が Person だろうが Person& だろうが Person&& だろうが、
完全転送コンストラクタじゃ無くてコピー・ムーブコンストラクタが呼ばれてほしい
• const や volatile が付いているかどうか
引数の型が const Person だろうが volatile Person だろうが const volatile
Person だろうが、完全転送コンストラクタじゃ無k(以下略
そんな時も type_traits
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
こんな式
!std::is_same<Person,
typename std::decay<T>::type
>::value
ホントはこれだと、配列や関数をポインタに変換しちゃうけど、今回の場合は問題なし
参照を取ってから、
更に cv 修飾を取る!!
値じゃなくて型が
欲しいから ::type
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<
typename T,
typename = typename std::enable_if<
!std::is_same<
Person,
typename std::decay<T>::type
>::value
>::type
>
explicit Person(T&& n);
Person(const Person&);
Person(Person&&);
…
};
まだダメでした…
class SP : public Person {
public:
SP(const SP& rhs)
: Person(rhs)
{ … }
SP(SP&& rhs)
: Person(std::move(rhs))
{ … }
…
};
T は
const SP&
T は
SP&&
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
完全転送コンストラクタは、
T が Person かその派生クラスの時には
無効化されて欲しい
そんな時も type_traits
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<
typename T,
typename = typename std::enable_if<
!std::is_base_of<Person,
typename std::decay<T>::type
>::value
>::type
>
explicit Person(T&& n);
…
};
typename std::decay<T>::type が
Person の派生クラスの時 true
Person そのものでもOK!
だいぶ長い…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<
typename T,
typename = typename std::enable_if<
!std::is_base_of<Person,
typename std::decay<T>::type
>::value
>::type
>
explicit Person(T&& n);
…
};
typename std::decay<T>::type が
Person の派生クラスの時 true
Person そのものでもOK!
だいぶ長い…
Errata に補足あり!
std::is_base_of<int, int> は
false になるよ!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<
typename T,
typename = std::enable_if_t<
!std::is_base_of<Person,
std::decay_t<T>
>::value
>
>
explicit Person(T&& n);
…
};
ちなみに C++14 だったら
もうちょっとスマート(かな?)
typename と ::type が
必要ない!
C++14 でも ::value は必要
(大人の事情により _v は入らず…)
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
でもまだ int を引数にとる
コンストラクタが追加されてない…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<typename T,
typename = std::enable_if_t<
!std::is_base_of<Person, std::decay_t<T>>::value
&&
!std::is_integral<std::remove_reference_t<T>>::value
>
>
explicit Person(T&& n)
: name(std::forward<T>(n))
{ … }
explicit Person(int idx)
: name(nameFromIdx(idx))
{ … }
…
private:
std::string name;
};
C++14 でも
超絶長い…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
SFINAE SUGEEEE!!!!
SFINAEのこと
もっと知りたい!!!
でも EMC++ にはそこまで書かれてない…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
そんなあなたに C++テンプレートテクニック 第2版
あのえぴさんと
アキラさんが
書いてるぞ!!!
C++11
完全対応!!!
電子書籍版も
あるぞ!!!
ちょっと読みづらいけど…
SFINAE
だけじゃなくて
テンプレート
全般!!!
まだ全部理解できてないけど…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
トレードオフ
1. オーバーロードを諦める
2. const T& で渡す
3. 値で渡す
4. タグディスパッチを使う
5. ユニバーサルリファレンスをとる
テンプレートに制約を設ける
完全転送を
諦める
(シンプル)
完全転送を
使う
(効率いい)
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
完全転送の欠点
1.完全転送できない場合がある
(完全じゃね~し… Item 30を参照)
2.クライアントが誤った引数を渡した時、
とち狂ったエラーメッセージが出る
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
とち狂ったメッセージの例
例えば、こんな感じに間違った場合…
Person p(u"Konrad Zuse");
巷で話題の
utf-16 リテラル
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
prog.cc: In instantiation of 'Person::Person(T&&) [with T = const char32_t (&)[5]; <template-parameter-1-2> = void]':
prog.cc:30:18: required from here
prog.cc:16:27: error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(const char32_t [5])'
: name(std::forward<T>(n))
^
In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0,
from prog.cc:2:
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: candidate: template<class _InputIterator, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(_InputIterator, _InputIterator, const _Alloc&)
basic_string(_InputIterator __beg, _InputIterator __end,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: template argument deduction/substitution failed:
prog.cc:16:27: note: candidate expects 3 arguments, 1 provided
: name(std::forward<T>(n))
^
In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0,
from prog.cc:2:
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc =
std::allocator<char>]
basic_string(basic_string&& __str, const _Alloc& __a)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate expects 2 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc =
std::allocator<char>]
basic_string(const basic_string& __str, const _Alloc& __a)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate expects 2 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::initializer_list<_Tp>, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc())
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::initializer_list<char>'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(basic_string&& __str) noexcept
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::__cxx11::basic_string<char>&&'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, _CharT, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>;
_Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(size_type __n, _CharT __c, const _Alloc& __a = _Alloc())
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate expects 3 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const char*'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits =
std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(const _CharT* __s, size_type __n,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate expects 3 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type,
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(const basic_string& __str, size_type __pos,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate expects 4 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type,
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(const basic_string& __str, size_type __pos,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate expects 3 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const basic_string& __str)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::__cxx11::basic_string<char>&'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _Alloc& __a)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::allocator<char>&'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string()
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate expects 0 arguments, 1 provided
GCC さん
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
prog.cc:16:4: error: no matching constructor for initialization of 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >')
: name(std::forward<T>(n))
^ ~~~~~~~~~~~~~~~~~~
prog.cc:30:9: note: in instantiation of function template specialization 'Person::Person<char32_t const (&)[5], void>' requested here
Person p(U"name");
^
/usr/local/libcxx-head/include/c++/v1/string:1326:40: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const allocator_type' (aka 'const std::__1::allocator<char>') for 1st argument
_LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a)
^
/usr/local/libcxx-head/include/c++/v1/string:1333:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const std::__1::basic_string<char>' for 1st argument
basic_string(const basic_string& __str);
^
/usr/local/libcxx-head/include/c++/v1/string:1338:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'std::__1::basic_string<char>' for 1st argument
basic_string(basic_string&& __str)
^
/usr/local/libcxx-head/include/c++/v1/string:1348:31: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const value_type *' (aka 'const char *') for 1st argument
_LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s);
^
/usr/local/libcxx-head/include/c++/v1/string:1369:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'initializer_list<value_type>' for 1st argument
basic_string(initializer_list<value_type> __il);
^
/usr/local/libcxx-head/include/c++/v1/string:1363:9: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
basic_string(_InputIterator __first, _InputIterator __last);
^
/usr/local/libcxx-head/include/c++/v1/string:1366:9: note: candidate constructor template not viable: requires 3 arguments, but 1 was provided
basic_string(_InputIterator __first, _InputIterator __last, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1323:31: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
_LIBCPP_INLINE_VISIBILITY basic_string()
^
/usr/local/libcxx-head/include/c++/v1/string:1346:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(basic_string&& __str, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1334:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(const basic_string& __str, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1350:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(const value_type* __s, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1352:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(const value_type* __s, size_type __n);
^
/usr/local/libcxx-head/include/c++/v1/string:1356:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(size_type __n, value_type __c);
^
/usr/local/libcxx-head/include/c++/v1/string:1371:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(initializer_list<value_type> __il, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1354:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided
basic_string(const value_type* __s, size_type __n, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1358:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided
basic_string(size_type __n, value_type __c, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1359:5: note: candidate constructor not viable: requires at least 2 arguments, but 1 was provided
basic_string(const basic_string& __str, size_type __pos, size_type __n = npos,
^
Clang さん
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
この例の場合、
ユニバーサルリファレンスの引数は
std::string の初期化に使われることが
分かっているので、
static_assert でチェックすることはできる。
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
class Person {
public:
template<typename T,
typename = std::enable_if_t<
!std::is_base_of<Person, std::decay_t<T>>::value
&&
!std::is_integral<std::remove_reference_t<T>>::value
>
>
explicit Person(T&& n)
: name(std::forward<T>(n))
{
// assert that a std::string can be created from a T object
static_assert(
std::is_constructible<std::string, T>::value,
"Parameter n can't be used to construct a std::string"
);
…
}
…
};
こんな感じでチェック!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
prog.cc: In instantiation of 'Person::Person(T&&) [with T = const char32_t (&)[5]; <template-parameter-1-2> = void]':
prog.cc:35:18: required from here
prog.cc:16:27: error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(const char32_t [5])'
: name(std::forward<T>(n))
^
In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0,
from prog.cc:2:
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: candidate: template<class _InputIterator, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(_InputIterator, _InputIterator, const _Alloc&)
basic_string(_InputIterator __beg, _InputIterator __end,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: template argument deduction/substitution failed:
prog.cc:16:27: note: candidate expects 3 arguments, 1 provided
: name(std::forward<T>(n))
^
In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0,
from prog.cc:2:
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc =
std::allocator<char>]
basic_string(basic_string&& __str, const _Alloc& __a)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate expects 2 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc =
std::allocator<char>]
basic_string(const basic_string& __str, const _Alloc& __a)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate expects 2 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::initializer_list<_Tp>, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc())
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::initializer_list<char>'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(basic_string&& __str) noexcept
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::__cxx11::basic_string<char>&&'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, _CharT, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>;
_Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(size_type __n, _CharT __c, const _Alloc& __a = _Alloc())
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate expects 3 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const char*'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits =
std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(const _CharT* __s, size_type __n,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate expects 3 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type,
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(const basic_string& __str, size_type __pos,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate expects 4 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type,
std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]
basic_string(const basic_string& __str, size_type __pos,
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate expects 3 arguments, 1 provided
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const basic_string& __str)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::__cxx11::basic_string<char>&'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string(const _Alloc& __a)
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::allocator<char>&'
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
basic_string()
^
/usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate expects 0 arguments, 1 provided
prog.cc:19:3: error: static assertion failed: Parameter n can't be used to construct a std::string
static_assert(
^
GCC さん
ここ!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
prog.cc:16:4: error: no matching constructor for initialization of 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >')
: name(std::forward<T>(n))
^ ~~~~~~~~~~~~~~~~~~
prog.cc:35:9: note: in instantiation of function template specialization 'Person::Person<char32_t const (&)[5], void>' requested here
Person p(U"name");
^
/usr/local/libcxx-head/include/c++/v1/string:1326:40: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const allocator_type' (aka 'const std::__1::allocator<char>') for 1st argument
_LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a)
^
/usr/local/libcxx-head/include/c++/v1/string:1333:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const std::__1::basic_string<char>' for 1st argument
basic_string(const basic_string& __str);
^
/usr/local/libcxx-head/include/c++/v1/string:1338:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'std::__1::basic_string<char>' for 1st argument
basic_string(basic_string&& __str)
^
/usr/local/libcxx-head/include/c++/v1/string:1348:31: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const value_type *' (aka 'const char *') for 1st argument
_LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s);
^
/usr/local/libcxx-head/include/c++/v1/string:1369:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'initializer_list<value_type>' for 1st argument
basic_string(initializer_list<value_type> __il);
^
/usr/local/libcxx-head/include/c++/v1/string:1363:9: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
basic_string(_InputIterator __first, _InputIterator __last);
^
/usr/local/libcxx-head/include/c++/v1/string:1366:9: note: candidate constructor template not viable: requires 3 arguments, but 1 was provided
basic_string(_InputIterator __first, _InputIterator __last, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1323:31: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
_LIBCPP_INLINE_VISIBILITY basic_string()
^
/usr/local/libcxx-head/include/c++/v1/string:1346:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(basic_string&& __str, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1334:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(const basic_string& __str, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1350:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(const value_type* __s, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1352:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(const value_type* __s, size_type __n);
^
/usr/local/libcxx-head/include/c++/v1/string:1356:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(size_type __n, value_type __c);
^
/usr/local/libcxx-head/include/c++/v1/string:1371:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
basic_string(initializer_list<value_type> __il, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1354:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided
basic_string(const value_type* __s, size_type __n, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1358:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided
basic_string(size_type __n, value_type __c, const allocator_type& __a);
^
/usr/local/libcxx-head/include/c++/v1/string:1359:5: note: candidate constructor not viable: requires at least 2 arguments, but 1 was provided
basic_string(const basic_string& __str, size_type __pos, size_type __n = npos,
^
prog.cc:19:3: error: static_assert failed "Parameter n can't be used to construct a std::string"
static_assert(
^
Clang さん
ここ!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
でも、今回の例の場合、
ホントはそもそも std::enable_if の条件に
std::is_constructible 使えばいいと
思うんだけど…
Errata には、コンパイラのエラーメッセージが、
「そんなコンストラクタ無いよ」ってなるので、
意味が変わっちゃうって書いてあるけど…
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
こんな感じ
class Person {
public:
template<typename T,
typename = std::enable_if_t<std::is_constructible<std::string, T>::value>
>
explicit Person(T&& n)
: name(std::forward<T>(n))
{
…
}
…
};
こんな感じで無効化!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
prog.cc: In function 'int main()':
prog.cc:26:18: error: no matching function for call to 'Person::Person(const char32_t [5])'
Person p(U"name");
^
prog.cc:18:2: note: candidate: Person::Person(Person&&)
Person(Person&&) = default;
^
prog.cc:18:2: note: no known conversion for argument 1 from 'const char32_t [5]' to
'Person&&'
prog.cc:17:2: note: candidate: Person::Person(const Person&)
Person(const Person&) = default;
^
prog.cc:17:2: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const
Person&'
prog.cc:11:11: note: candidate: template<class T, class> Person::Person(T&&)
explicit Person(T&& n)
^
prog.cc:11:11: note: template argument deduction/substitution failed:
GCC さん
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
prog.cc:26:9: error: no matching constructor for initialization of 'Person'
Person p(U"name");
^ ~~~~~~~
prog.cc:17:2: note: candidate constructor not viable: no known conversion from 'const
char32_t [5]' to 'const Person' for 1st argument
Person(const Person&) = default;
^
prog.cc:18:2: note: candidate constructor not viable: no known conversion from 'const
char32_t [5]' to 'Person' for 1st argument
Person(Person&&) = default;
^
/usr/local/libcxx-head/include/c++/v1/type_traits:244:78: note: candidate template ignored:
disabled by 'enable_if' [with T = char32_t const (&)[5]]
template <bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp,
_Tp>::type;
^
Clang さん
Clang さんすごい!
Item 27: Familiarize yourself with alternatives
to overloading on universal references.
覚えておくこと
• ユニバーサルリファレンスとオーバーロードの組み合わせの代替案
には、異なる関数名を使用する、パラメータをconstへの左辺値参
照で渡す、パラメータを値で渡す、タグディスパッチを使う、が含まれ
る。
• std::enable_if を通じてテンプレートを制約することで、ユニ
バーサルリファレンスとオーバーロードを同時に使用できるが、それ
はコンパイラがユニバーサルリファレンスのオーバーロードを使用す
る条件を制御する。
• ユニバーサルリファレンスはたいてい効率上の利点があるが、概し
て使い勝手の点で欠点もある。

More Related Content

PDF
effective modern c++ chapeter36
PDF
Effective Modern C++ 勉強会#1 Item3,4
PDF
templateとautoの型推論
PDF
Effective Modern C++ 勉強会#3 Item16
PPTX
Effective Modern C++勉強会#4 Item 17, 18資料
PDF
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
PPTX
Emcpp0506
PDF
組み込みでこそC++を使う10の理由
effective modern c++ chapeter36
Effective Modern C++ 勉強会#1 Item3,4
templateとautoの型推論
Effective Modern C++ 勉強会#3 Item16
Effective Modern C++勉強会#4 Item 17, 18資料
Boost.勉強会 #21 札幌「C++1zにstring_viewが導入されてうれしいので紹介します」
Emcpp0506
組み込みでこそC++を使う10の理由

What's hot (20)

PDF
containerdの概要と最近の機能
PPTX
Effective Modern C++ Item 9 and 10
PDF
WebAssembly向け多倍長演算の実装
PDF
20分くらいでわかった気分になれるC++20コルーチン
PDF
中3女子でもわかる constexpr
PPTX
クソザコ鳥頭が非順序連想コンテナに入門してみた
PDF
F#入門 ~関数プログラミングとは何か~
PDF
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
PPTX
Wiresharkの解析プラグインを作る ssmjp 201409
PDF
Using Xcore with Xtext
PDF
Constexpr 中3女子テクニック
PDF
C#でわかる こわくないMonad
PDF
Emcjp item21
PDF
emc++ chapter32
PDF
オブジェクト指向できていますか?
PDF
アプリ屋もDockerをドカドカ使おう ~ Docker入門
PDF
中3女子が狂える本当に気持ちのいい constexpr
PDF
Effective Modern C++ 勉強会#3 Item 15
PDF
Reinventing the Transaction Script (NDC London 2020)
PPTX
C#言語機能の作り方
containerdの概要と最近の機能
Effective Modern C++ Item 9 and 10
WebAssembly向け多倍長演算の実装
20分くらいでわかった気分になれるC++20コルーチン
中3女子でもわかる constexpr
クソザコ鳥頭が非順序連想コンテナに入門してみた
F#入門 ~関数プログラミングとは何か~
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
Wiresharkの解析プラグインを作る ssmjp 201409
Using Xcore with Xtext
Constexpr 中3女子テクニック
C#でわかる こわくないMonad
Emcjp item21
emc++ chapter32
オブジェクト指向できていますか?
アプリ屋もDockerをドカドカ使おう ~ Docker入門
中3女子が狂える本当に気持ちのいい constexpr
Effective Modern C++ 勉強会#3 Item 15
Reinventing the Transaction Script (NDC London 2020)
C#言語機能の作り方
Ad

Viewers also liked (16)

PDF
Effective Modern C++ 勉強会 Item26
PDF
Effective modern-c++#9
PPTX
Effective modern C++ 勉強会 #3 Item 12
PPTX
Effective Modern C++ 勉強会 Item 22
PPTX
Effective Modern C++ study group Item39
PPTX
Effective Modern C++勉強会#2 Item 11(,12)
PDF
Effective Modern C++ 勉強会#6 Item25
PDF
Effective Modern C++ 勉強会#8 Item38
PPTX
Effective modern c++ 8
PDF
Effective Modern C++ Item 24: Distinguish universal references from rvalue re...
PDF
Emcjp item33,34
PDF
emcjp Item 42
PDF
Emcpp item31
PDF
Emcpp item41
PDF
Effective Modern C++ 読書会 Item 35
PPTX
Effective modern c++ 5
Effective Modern C++ 勉強会 Item26
Effective modern-c++#9
Effective modern C++ 勉強会 #3 Item 12
Effective Modern C++ 勉強会 Item 22
Effective Modern C++ study group Item39
Effective Modern C++勉強会#2 Item 11(,12)
Effective Modern C++ 勉強会#6 Item25
Effective Modern C++ 勉強会#8 Item38
Effective modern c++ 8
Effective Modern C++ Item 24: Distinguish universal references from rvalue re...
Emcjp item33,34
emcjp Item 42
Emcpp item31
Emcpp item41
Effective Modern C++ 読書会 Item 35
Effective modern c++ 5
Ad

Recently uploaded (20)

PPTX
MYSQL Presentation for SQL database connectivity
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PPTX
SOPHOS-XG Firewall Administrator PPT.pptx
PPTX
1. Introduction to Computer Programming.pptx
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Approach and Philosophy of On baking technology
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
A comparative analysis of optical character recognition models for extracting...
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Spectroscopy.pptx food analysis technology
PPTX
Programs and apps: productivity, graphics, security and other tools
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Encapsulation theory and applications.pdf
PDF
cuic standard and advanced reporting.pdf
MYSQL Presentation for SQL database connectivity
Assigned Numbers - 2025 - Bluetooth® Document
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Empathic Computing: Creating Shared Understanding
Accuracy of neural networks in brain wave diagnosis of schizophrenia
SOPHOS-XG Firewall Administrator PPT.pptx
1. Introduction to Computer Programming.pptx
Building Integrated photovoltaic BIPV_UPV.pdf
Approach and Philosophy of On baking technology
Unlocking AI with Model Context Protocol (MCP)
NewMind AI Weekly Chronicles - August'25-Week II
MIND Revenue Release Quarter 2 2025 Press Release
A comparative analysis of optical character recognition models for extracting...
Diabetes mellitus diagnosis method based random forest with bat algorithm
Spectroscopy.pptx food analysis technology
Programs and apps: productivity, graphics, security and other tools
Digital-Transformation-Roadmap-for-Companies.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Encapsulation theory and applications.pdf
cuic standard and advanced reporting.pdf

Effective Modern C++ 勉強会#7 Item 27

  • 1. Effective Modern C++ 勉強会#7 Item 27 刈谷 満(@kariya_mitsuru) 2015/6/17
  • 2. Item 27: Familiarize yourself with alternatives to overloading on universal references. ユニバーサルリファレンスを伴う オーバーロードの代替案に 慣れ親しもう
  • 3. Item 27: Familiarize yourself with alternatives to overloading on universal references. Item 26 で見たように、ユニバーサルリ ファレンスを伴うオーバーロードはヤバい でも、オーバーロード便利 (ただし、思った通りに動いてくれれば)
  • 4. Item 27: Familiarize yourself with alternatives to overloading on universal references. こんな代替案がある 1. オーバーロードを諦める 2. const T& で渡す 3. 値で渡す 4. タグディスパッチを使う 5. ユニバーサルリファレンスをとるテンプレートに 制約を設ける
  • 5. Item 27: Familiarize yourself with alternatives to overloading on universal references. 1.オーバーロードを諦める そのまんま オーバーロードするから訳が分からなくなる ⇓ オーバーロードしなきゃいんじゃね?
  • 6. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> void logAndAdd(T&& name); void logAndAdd(int idx);
  • 7. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> void logAndAdd(T&& name); void logAndAdd(int idx); こうじゃ template<typename T> void logAndAddName(T&& name); void logAndAddNameIdx(int idx);
  • 8. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> void logAndAdd(T&& name); void logAndAdd(int idx); こうじゃ template<typename T> void logAndAddName(T&& name); void logAndAddNameIdx(int idx); 全て解決!
  • 9. Item 27: Familiarize yourself with alternatives to overloading on universal references. 欠点 コンストラクタには無力 (コンストラクタには名前が無い) 本には名前固定って書いてあるけど、名前無いっすよ… §12[class.ctor]/p.1 "Constructors do not have names." てか、やっぱオーバーロード使いたくね?
  • 10. Item 27: Familiarize yourself with alternatives to overloading on universal references. 2.const T& で渡す そのまんま ユニバーサルリファレンス使うから訳がわからなくなる ⇓ ユニバーサルリファレンス使わなきゃいんじゃね?
  • 11. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> void logAndAdd(T&& name); void logAndAdd(int idx);
  • 12. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> void logAndAdd(T&& name); void logAndAdd(int idx); こうじゃ void logAndAdd(const std::string& name); void logAndAdd(int idx);
  • 13. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> void logAndAdd(T&& name); void logAndAdd(int idx); こうじゃ void logAndAdd(const std::string& name); void logAndAdd(int idx); 全て解決!
  • 14. Item 27: Familiarize yourself with alternatives to overloading on universal references. 欠点 ユニバーサルリファレンス使う方法ほど 効率的じゃない (でもシンプルさは魅力的) てか、やっぱユニバーサルリファレンス 使いたくね?
  • 15. Item 27: Familiarize yourself with alternatives to overloading on universal references. 3.値で渡す そのまんま …え?効率は? 実はわりと効率がいい(場合も多い) けど、詳細は Item 41 のお楽しみ
  • 16. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> explicit Person(T&& n) : name(std::forward<T>(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {}
  • 17. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> explicit Person(T&& n) : name(std::forward<T>(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} こうじゃ explicit Person(std::string n) : name(std::move(n)) {} explicit Perosn(int idx) : name(nameFromIdx(idx)) {}
  • 18. Item 27: Familiarize yourself with alternatives to overloading on universal references. これを template<typename T> explicit Person(T&& n) : name(std::forward<T>(n)) {} explicit Person(int idx) : name(nameFromIdx(idx)) {} こうじゃ explicit Person(std::string n) : name(std::move(n)) {} explicit Perosn(int idx) : name(nameFromIdx(idx)) {} 全て解決!
  • 19. Item 27: Familiarize yourself with alternatives to overloading on universal references. 欠点 この例ならわりと効率いいけど、 ユニバーサルリファレンスほどじゃないし、 ムーブが効率悪い場合には使えない。(std::array とか…) Item 41 を知らない人が見ると、「効率悪い!」と言われて、 最悪直される(※ 個人の感想です) 0 はともかく、NULL を渡すと int バージョン呼ばれる。 (けど、これに限らないし、Item 8 読め)
  • 20. Item 27: Familiarize yourself with alternatives to overloading on universal references. 4.タグディスパッチを使う やっぱ完全転送したい!!! ⇓ みんな大好き、タグディスパッチ
  • 21. Item 27: Familiarize yourself with alternatives to overloading on universal references. わ あ い タ グ デ ィ ス パ ッ チ め う め う タ グ デ ィ ス パ ッ チ 大 好 き め う ©芽兎めう
  • 22. Item 27: Familiarize yourself with alternatives to overloading on universal references. ユニバーサルリファレンスの問題点 あらゆる引数に完全一致する
  • 23. Item 27: Familiarize yourself with alternatives to overloading on universal references. 引 数 が 一 つ し か な い と 錯 覚 し て い た ? ©藍染惣右介
  • 24. Item 27: Familiarize yourself with alternatives to overloading on universal references. 解決策 ユニバーサルリファレンス以外 の引数で、オーバーロード解決 を制御すれば良い
  • 25. Item 27: Familiarize yourself with alternatives to overloading on universal references. 元のコード std::multiset<std::string> names; template<typename T> void logAndAdd(T&& name) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(std::forward<T>(name)); } これに、int を取るオーバーロードを追加したい
  • 26. Item 27: Familiarize yourself with alternatives to overloading on universal references. logAndAdd のオーバーロードを追加するんじゃなくて、 logAndAdd 内で実際に処理する関数 logAndAddImpl に処理を委譲する ⇓ この際、T が int の場合用と そうじゃない場合用の関数を作って それらの関数に追加の引数を追加して、 それらの型(タグ)が完璧に異なれば良い
  • 27. Item 27: Familiarize yourself with alternatives to overloading on universal references. クライアントが呼び出す関数 template<typename T> void logAndAdd(T&& name) { logAndAddImpl(name, 型①か型②); } 実際に処理する関数 void logAndAddImpl(T&& name, 型①) { int 以外の時の処理がここに } void logAndAddImpl(int idx, 型②) { int の時の処理がここに }T が int の以外時は「型①」 T が int の時は「型②」 つまり、こんな感じにすれば良い
  • 28. Item 27: Familiarize yourself with alternatives to overloading on universal references. クライアントが呼び出す関数 template<typename T> void logAndAdd(T&& name) { logAndAddImpl(name, 型①か型②); } 実際に処理する関数 void logAndAddImpl(T&& name, 型①) { int 以外の時の処理がここに } void logAndAddImpl(int idx, 型②) { int の時の処理がここに }T が int の以外時は「型①」 T が int の時は「型②」 つまり、こんな感じにすれば良い で? 「型①か型②」って?
  • 29. Item 27: Familiarize yourself with alternatives to overloading on universal references. これが「型①か型②」だ!!! template<typename T> void logAndAdd(T&& name) { logAndAddImpl(std::forward<T>(name), std::is_integral<T>()); } 引数だから、() を付 けてオブジェクト生成 T が int 以外の時は「std::false_type」から派生 T が int の時は「std::true_type」から派生
  • 30. Item 27: Familiarize yourself with alternatives to overloading on universal references. これが「型①か型②」だ!!! template<typename T> void logAndAdd(T&& name) { logAndAddImpl(std::forward<T>(name), std::is_integral<T>()); } 引数だから、() を付 けてオブジェクト生成 T が int 以外の時は「std::false_type」から派生 T が int の時は「std::true_type」から派生 でもちょっと うまくない…
  • 31. Item 27: Familiarize yourself with alternatives to overloading on universal references. int i = 10; … logAndAdd(i); template<typename T> void logAndAdd(T&& name) { logAndAddImpl( std::forward<T>(name), std::is_integral<T>()); } うまくない理由 こんな感じで呼び出すと… T が int& になっちゃう ⇒参照型は整数型じゃないから、 std::false_typeになっちゃう
  • 32. Item 27: Familiarize yourself with alternatives to overloading on universal references. これが正しい「型①か型②」だ!!! template<typename T> void logAndAdd(T&& name) { logAndAddImpl( std::forward<T>(name), std::is_integral<typename std::remove_reference<T>::type>()); } T が int っぽくない時は「std::false_type」 T が int っぽい時は「std::true_type」 T から「参照」を消す
  • 33. Item 27: Familiarize yourself with alternatives to overloading on universal references. ちな、処理本体側はこんな感じ // int 以外用の関数 template<typename T> void logAndAddImpl(T&& name, std::false_type) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(std::forward<T>(name)); } std::string nameFromIdx(int idx); // int 用の関数 void logAndAddImpl(int idx, std::true_type) { logAndAdd(nameFromIdx(idx)); } オーバーロード解決の ためだけにあるから、 パラメータ名は 付けてない オーバーロード解決の ためだけにあるから、 パラメータ名は 付けてない idx から名前に 変換したら、 再度 logAndAdd を 呼び出す
  • 34. Item 27: Familiarize yourself with alternatives to overloading on universal references. ちな、処理本体側はこんな感じ // int 以外用の関数 template<typename T> void logAndAddImpl(T&& name, std::false_type) { auto now = std::chrono::system_clock::now(); log(now, "logAndAdd"); names.emplace(std::forward<T>(name)); } std::string nameFromIdx(int idx); // int 用の関数 void logAndAddImpl(int idx, std::true_type) { logAndAdd(nameFromIdx(idx)); } オーバーロード解決の ためだけにあるから、 パラメータ名は 付けてない オーバーロード解決の ためだけにあるから、 パラメータ名は 付けてない idx から名前に 変換したら、 再度 logAndAdd を 呼び出す 賢いコンパイラなら、 最後のパラメータ使ってないから 消してくれるかも… こうすれば、ログ出力コード 二重にメンテしなくて済む…
  • 35. Item 27: Familiarize yourself with alternatives to overloading on universal references. タグディスパッチSUGEEEE!!!! タグディスパッチのこと もっと知りたい!!! でも EMC++ にはそこまで書かれてない…
  • 36. Item 27: Familiarize yourself with alternatives to overloading on universal references. そんなあなたに C++テンプレートテクニック 第2版 あのえぴさんと アキラさんが 書いてるぞ!!! C++11 完全対応!!! 電子書籍版も あるぞ!!! ちょっと読みづらいけど… タグディスパッチ だけじゃなくて テンプレート 全般!!! まだ全部理解できてないけど…
  • 37. Item 27: Familiarize yourself with alternatives to overloading on universal references. タグディスパッチいいよ、タグディスパッチ もう何もかもタグディスパッチでよくね?
  • 38. Item 27: Familiarize yourself with alternatives to overloading on universal references. 欠点 コンストラクタには無力 (またっすか…)
  • 39. Item 27: Familiarize yourself with alternatives to overloading on universal references. 例のダメなクラス class Person { public: template<typename T> explicit Person(T&& n) : name(std::forward<Person&>(n)) {} explicit Person(int idx); Person(const Person& rhs); Person(Person&& rhs); … }; 完全転送 コンストラクタ int コンストラクタ コピー コンストラクタ ムーブ コンストラクタ
  • 40. Item 27: Familiarize yourself with alternatives to overloading on universal references. 例のダメなクラス class Person { public: template<typename T> explicit Person(T&& n) : name(std::forward<Person&>(n)) {} explicit Person(int idx); Person(const Person& rhs); Person(Person&& rhs); … }; Person p("Nancy"); auto cloneOfP(p); 全部完全転送… 上はいいけど、下に対して コピーコンストラクタが 呼ばれない…
  • 41. Item 27: Familiarize yourself with alternatives to overloading on universal references. 5.ユニバーサルリファレンスをとるテンプレートに制約を設ける そのまんま ユニバーサルリファレンスを取る関数が 呼ばれて欲しくない時まで呼ばれちゃう ⇓ 関数を呼ばれて欲しい時だけ 有効にすればいんじゃね?
  • 42. Item 27: Familiarize yourself with alternatives to overloading on universal references. 「関数を呼ばれて欲しい時だけ有効に」? そのためのメタ関数が type_traits に! std::enable_if SFINAE と呼ばれる 機構を使ってる
  • 43. Item 27: Familiarize yourself with alternatives to overloading on universal references. 使い方はこんな感じ class Person { public: template<typename T, typename = typename std::enable_if<condition>::type> explicit Person(T&& n); … }; この condition の部分に、このコンストラク タを使っても良い条件式を書く。 ただし、コンパイル時定数のみ!! 関数テンプレートのデフォルトテンプレート引数 (C++11の新機能!)を enable_if にする
  • 44. Item 27: Familiarize yourself with alternatives to overloading on universal references. では、今回の場合、どんな時に呼ばれて欲しいのか? ⇓ T が Person じゃない時 T が Person の場合、コピーコンストラクタや ムーブコンストラクタが呼ばれて欲しいから そんな時も type_traits
  • 45. Item 27: Familiarize yourself with alternatives to overloading on universal references. こんな式 !std::is_same<Person, T>::value 先頭の!に注意 Person と T が 同じ型の時 true 型じゃなくて bool 値が欲しいから ::value
  • 46. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template< typename T, typename = typename std::enable_if< !std::is_same<Person, T>::value >::type > explicit Person(T&& n); Person(const Person&); Person(Person&&); … }; ダメでした… Person p("Nancy"); auto cloneOfP(p); T は const char(&)[6] T は Person& p は左辺値だから T が左辺値参照に…
  • 47. Item 27: Familiarize yourself with alternatives to overloading on universal references. T と Person を比較する時には、以下の2点を無視したい • 参照かどうか 引数の型が Person だろうが Person& だろうが Person&& だろうが、 完全転送コンストラクタじゃ無くてコピー・ムーブコンストラクタが呼ばれてほしい • const や volatile が付いているかどうか 引数の型が const Person だろうが volatile Person だろうが const volatile Person だろうが、完全転送コンストラクタじゃ無k(以下略 そんな時も type_traits
  • 48. Item 27: Familiarize yourself with alternatives to overloading on universal references. こんな式 !std::is_same<Person, typename std::decay<T>::type >::value ホントはこれだと、配列や関数をポインタに変換しちゃうけど、今回の場合は問題なし 参照を取ってから、 更に cv 修飾を取る!! 値じゃなくて型が 欲しいから ::type
  • 49. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template< typename T, typename = typename std::enable_if< !std::is_same< Person, typename std::decay<T>::type >::value >::type > explicit Person(T&& n); Person(const Person&); Person(Person&&); … }; まだダメでした… class SP : public Person { public: SP(const SP& rhs) : Person(rhs) { … } SP(SP&& rhs) : Person(std::move(rhs)) { … } … }; T は const SP& T は SP&&
  • 50. Item 27: Familiarize yourself with alternatives to overloading on universal references. 完全転送コンストラクタは、 T が Person かその派生クラスの時には 無効化されて欲しい そんな時も type_traits
  • 51. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template< typename T, typename = typename std::enable_if< !std::is_base_of<Person, typename std::decay<T>::type >::value >::type > explicit Person(T&& n); … }; typename std::decay<T>::type が Person の派生クラスの時 true Person そのものでもOK! だいぶ長い…
  • 52. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template< typename T, typename = typename std::enable_if< !std::is_base_of<Person, typename std::decay<T>::type >::value >::type > explicit Person(T&& n); … }; typename std::decay<T>::type が Person の派生クラスの時 true Person そのものでもOK! だいぶ長い… Errata に補足あり! std::is_base_of<int, int> は false になるよ!
  • 53. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template< typename T, typename = std::enable_if_t< !std::is_base_of<Person, std::decay_t<T> >::value > > explicit Person(T&& n); … }; ちなみに C++14 だったら もうちょっとスマート(かな?) typename と ::type が 必要ない! C++14 でも ::value は必要 (大人の事情により _v は入らず…)
  • 54. Item 27: Familiarize yourself with alternatives to overloading on universal references. でもまだ int を引数にとる コンストラクタが追加されてない…
  • 55. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template<typename T, typename = std::enable_if_t< !std::is_base_of<Person, std::decay_t<T>>::value && !std::is_integral<std::remove_reference_t<T>>::value > > explicit Person(T&& n) : name(std::forward<T>(n)) { … } explicit Person(int idx) : name(nameFromIdx(idx)) { … } … private: std::string name; }; C++14 でも 超絶長い…
  • 56. Item 27: Familiarize yourself with alternatives to overloading on universal references. SFINAE SUGEEEE!!!! SFINAEのこと もっと知りたい!!! でも EMC++ にはそこまで書かれてない…
  • 57. Item 27: Familiarize yourself with alternatives to overloading on universal references. そんなあなたに C++テンプレートテクニック 第2版 あのえぴさんと アキラさんが 書いてるぞ!!! C++11 完全対応!!! 電子書籍版も あるぞ!!! ちょっと読みづらいけど… SFINAE だけじゃなくて テンプレート 全般!!! まだ全部理解できてないけど…
  • 58. Item 27: Familiarize yourself with alternatives to overloading on universal references. トレードオフ 1. オーバーロードを諦める 2. const T& で渡す 3. 値で渡す 4. タグディスパッチを使う 5. ユニバーサルリファレンスをとる テンプレートに制約を設ける 完全転送を 諦める (シンプル) 完全転送を 使う (効率いい)
  • 59. Item 27: Familiarize yourself with alternatives to overloading on universal references. 完全転送の欠点 1.完全転送できない場合がある (完全じゃね~し… Item 30を参照) 2.クライアントが誤った引数を渡した時、 とち狂ったエラーメッセージが出る
  • 60. Item 27: Familiarize yourself with alternatives to overloading on universal references. とち狂ったメッセージの例 例えば、こんな感じに間違った場合… Person p(u"Konrad Zuse"); 巷で話題の utf-16 リテラル
  • 61. Item 27: Familiarize yourself with alternatives to overloading on universal references. prog.cc: In instantiation of 'Person::Person(T&&) [with T = const char32_t (&)[5]; <template-parameter-1-2> = void]': prog.cc:30:18: required from here prog.cc:16:27: error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(const char32_t [5])' : name(std::forward<T>(n)) ^ In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0, from prog.cc:2: /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: candidate: template<class _InputIterator, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(_InputIterator, _InputIterator, const _Alloc&) basic_string(_InputIterator __beg, _InputIterator __end, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: template argument deduction/substitution failed: prog.cc:16:27: note: candidate expects 3 arguments, 1 provided : name(std::forward<T>(n)) ^ In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0, from prog.cc:2: /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(basic_string&& __str, const _Alloc& __a) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate expects 2 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const basic_string& __str, const _Alloc& __a) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate expects 2 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::initializer_list<_Tp>, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc()) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::initializer_list<char>' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(basic_string&& __str) noexcept ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::__cxx11::basic_string<char>&&' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, _CharT, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(size_type __n, _CharT __c, const _Alloc& __a = _Alloc()) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate expects 3 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const char*' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(const _CharT* __s, size_type __n, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate expects 3 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(const basic_string& __str, size_type __pos, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate expects 4 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(const basic_string& __str, size_type __pos, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate expects 3 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const basic_string& __str) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::__cxx11::basic_string<char>&' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const _Alloc& __a) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::allocator<char>&' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string() ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate expects 0 arguments, 1 provided GCC さん
  • 62. Item 27: Familiarize yourself with alternatives to overloading on universal references. prog.cc:16:4: error: no matching constructor for initialization of 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') : name(std::forward<T>(n)) ^ ~~~~~~~~~~~~~~~~~~ prog.cc:30:9: note: in instantiation of function template specialization 'Person::Person<char32_t const (&)[5], void>' requested here Person p(U"name"); ^ /usr/local/libcxx-head/include/c++/v1/string:1326:40: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const allocator_type' (aka 'const std::__1::allocator<char>') for 1st argument _LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a) ^ /usr/local/libcxx-head/include/c++/v1/string:1333:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const std::__1::basic_string<char>' for 1st argument basic_string(const basic_string& __str); ^ /usr/local/libcxx-head/include/c++/v1/string:1338:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'std::__1::basic_string<char>' for 1st argument basic_string(basic_string&& __str) ^ /usr/local/libcxx-head/include/c++/v1/string:1348:31: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const value_type *' (aka 'const char *') for 1st argument _LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s); ^ /usr/local/libcxx-head/include/c++/v1/string:1369:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'initializer_list<value_type>' for 1st argument basic_string(initializer_list<value_type> __il); ^ /usr/local/libcxx-head/include/c++/v1/string:1363:9: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided basic_string(_InputIterator __first, _InputIterator __last); ^ /usr/local/libcxx-head/include/c++/v1/string:1366:9: note: candidate constructor template not viable: requires 3 arguments, but 1 was provided basic_string(_InputIterator __first, _InputIterator __last, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1323:31: note: candidate constructor not viable: requires 0 arguments, but 1 was provided _LIBCPP_INLINE_VISIBILITY basic_string() ^ /usr/local/libcxx-head/include/c++/v1/string:1346:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(basic_string&& __str, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1334:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(const basic_string& __str, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1350:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(const value_type* __s, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1352:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(const value_type* __s, size_type __n); ^ /usr/local/libcxx-head/include/c++/v1/string:1356:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(size_type __n, value_type __c); ^ /usr/local/libcxx-head/include/c++/v1/string:1371:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(initializer_list<value_type> __il, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1354:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided basic_string(const value_type* __s, size_type __n, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1358:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided basic_string(size_type __n, value_type __c, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1359:5: note: candidate constructor not viable: requires at least 2 arguments, but 1 was provided basic_string(const basic_string& __str, size_type __pos, size_type __n = npos, ^ Clang さん
  • 63. Item 27: Familiarize yourself with alternatives to overloading on universal references. この例の場合、 ユニバーサルリファレンスの引数は std::string の初期化に使われることが 分かっているので、 static_assert でチェックすることはできる。
  • 64. Item 27: Familiarize yourself with alternatives to overloading on universal references. class Person { public: template<typename T, typename = std::enable_if_t< !std::is_base_of<Person, std::decay_t<T>>::value && !std::is_integral<std::remove_reference_t<T>>::value > > explicit Person(T&& n) : name(std::forward<T>(n)) { // assert that a std::string can be created from a T object static_assert( std::is_constructible<std::string, T>::value, "Parameter n can't be used to construct a std::string" ); … } … }; こんな感じでチェック!
  • 65. Item 27: Familiarize yourself with alternatives to overloading on universal references. prog.cc: In instantiation of 'Person::Person(T&&) [with T = const char32_t (&)[5]; <template-parameter-1-2> = void]': prog.cc:35:18: required from here prog.cc:16:27: error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(const char32_t [5])' : name(std::forward<T>(n)) ^ In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0, from prog.cc:2: /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: candidate: template<class _InputIterator, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(_InputIterator, _InputIterator, const _Alloc&) basic_string(_InputIterator __beg, _InputIterator __end, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:535:9: note: template argument deduction/substitution failed: prog.cc:16:27: note: candidate expects 3 arguments, 1 provided : name(std::forward<T>(n)) ^ In file included from /usr/local/gcc-head/include/c++/6.0.0/string:52:0, from prog.cc:2: /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(basic_string&& __str, const _Alloc& __a) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:512:7: note: candidate expects 2 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const basic_string& __str, const _Alloc& __a) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:508:7: note: candidate expects 2 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::initializer_list<_Tp>, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc()) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:504:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::initializer_list<char>' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(basic_string&& __str) noexcept ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:477:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'std::__cxx11::basic_string<char>&&' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, _CharT, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(size_type __n, _CharT __c, const _Alloc& __a = _Alloc()) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:465:7: note: candidate expects 3 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:455:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const char*' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(const _CharT* __s, size_type __n, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:445:7: note: candidate expects 3 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(const basic_string& __str, size_type __pos, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:427:7: note: candidate expects 4 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int] basic_string(const basic_string& __str, size_type __pos, ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:411:7: note: candidate expects 3 arguments, 1 provided /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const basic_string& __str) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:399:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::__cxx11::basic_string<char>&' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string(const _Alloc& __a) ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:391:7: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const std::allocator<char>&' /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] basic_string() ^ /usr/local/gcc-head/include/c++/6.0.0/bits/basic_string.h:380:7: note: candidate expects 0 arguments, 1 provided prog.cc:19:3: error: static assertion failed: Parameter n can't be used to construct a std::string static_assert( ^ GCC さん ここ!
  • 66. Item 27: Familiarize yourself with alternatives to overloading on universal references. prog.cc:16:4: error: no matching constructor for initialization of 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') : name(std::forward<T>(n)) ^ ~~~~~~~~~~~~~~~~~~ prog.cc:35:9: note: in instantiation of function template specialization 'Person::Person<char32_t const (&)[5], void>' requested here Person p(U"name"); ^ /usr/local/libcxx-head/include/c++/v1/string:1326:40: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const allocator_type' (aka 'const std::__1::allocator<char>') for 1st argument _LIBCPP_INLINE_VISIBILITY explicit basic_string(const allocator_type& __a) ^ /usr/local/libcxx-head/include/c++/v1/string:1333:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const std::__1::basic_string<char>' for 1st argument basic_string(const basic_string& __str); ^ /usr/local/libcxx-head/include/c++/v1/string:1338:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'std::__1::basic_string<char>' for 1st argument basic_string(basic_string&& __str) ^ /usr/local/libcxx-head/include/c++/v1/string:1348:31: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'const value_type *' (aka 'const char *') for 1st argument _LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s); ^ /usr/local/libcxx-head/include/c++/v1/string:1369:5: note: candidate constructor not viable: no known conversion from 'char32_t const[5]' to 'initializer_list<value_type>' for 1st argument basic_string(initializer_list<value_type> __il); ^ /usr/local/libcxx-head/include/c++/v1/string:1363:9: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided basic_string(_InputIterator __first, _InputIterator __last); ^ /usr/local/libcxx-head/include/c++/v1/string:1366:9: note: candidate constructor template not viable: requires 3 arguments, but 1 was provided basic_string(_InputIterator __first, _InputIterator __last, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1323:31: note: candidate constructor not viable: requires 0 arguments, but 1 was provided _LIBCPP_INLINE_VISIBILITY basic_string() ^ /usr/local/libcxx-head/include/c++/v1/string:1346:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(basic_string&& __str, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1334:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(const basic_string& __str, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1350:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(const value_type* __s, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1352:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(const value_type* __s, size_type __n); ^ /usr/local/libcxx-head/include/c++/v1/string:1356:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(size_type __n, value_type __c); ^ /usr/local/libcxx-head/include/c++/v1/string:1371:5: note: candidate constructor not viable: requires 2 arguments, but 1 was provided basic_string(initializer_list<value_type> __il, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1354:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided basic_string(const value_type* __s, size_type __n, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1358:5: note: candidate constructor not viable: requires 3 arguments, but 1 was provided basic_string(size_type __n, value_type __c, const allocator_type& __a); ^ /usr/local/libcxx-head/include/c++/v1/string:1359:5: note: candidate constructor not viable: requires at least 2 arguments, but 1 was provided basic_string(const basic_string& __str, size_type __pos, size_type __n = npos, ^ prog.cc:19:3: error: static_assert failed "Parameter n can't be used to construct a std::string" static_assert( ^ Clang さん ここ!
  • 67. Item 27: Familiarize yourself with alternatives to overloading on universal references. でも、今回の例の場合、 ホントはそもそも std::enable_if の条件に std::is_constructible 使えばいいと 思うんだけど… Errata には、コンパイラのエラーメッセージが、 「そんなコンストラクタ無いよ」ってなるので、 意味が変わっちゃうって書いてあるけど…
  • 68. Item 27: Familiarize yourself with alternatives to overloading on universal references. こんな感じ class Person { public: template<typename T, typename = std::enable_if_t<std::is_constructible<std::string, T>::value> > explicit Person(T&& n) : name(std::forward<T>(n)) { … } … }; こんな感じで無効化!
  • 69. Item 27: Familiarize yourself with alternatives to overloading on universal references. prog.cc: In function 'int main()': prog.cc:26:18: error: no matching function for call to 'Person::Person(const char32_t [5])' Person p(U"name"); ^ prog.cc:18:2: note: candidate: Person::Person(Person&&) Person(Person&&) = default; ^ prog.cc:18:2: note: no known conversion for argument 1 from 'const char32_t [5]' to 'Person&&' prog.cc:17:2: note: candidate: Person::Person(const Person&) Person(const Person&) = default; ^ prog.cc:17:2: note: no known conversion for argument 1 from 'const char32_t [5]' to 'const Person&' prog.cc:11:11: note: candidate: template<class T, class> Person::Person(T&&) explicit Person(T&& n) ^ prog.cc:11:11: note: template argument deduction/substitution failed: GCC さん
  • 70. Item 27: Familiarize yourself with alternatives to overloading on universal references. prog.cc:26:9: error: no matching constructor for initialization of 'Person' Person p(U"name"); ^ ~~~~~~~ prog.cc:17:2: note: candidate constructor not viable: no known conversion from 'const char32_t [5]' to 'const Person' for 1st argument Person(const Person&) = default; ^ prog.cc:18:2: note: candidate constructor not viable: no known conversion from 'const char32_t [5]' to 'Person' for 1st argument Person(Person&&) = default; ^ /usr/local/libcxx-head/include/c++/v1/type_traits:244:78: note: candidate template ignored: disabled by 'enable_if' [with T = char32_t const (&)[5]] template <bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type; ^ Clang さん Clang さんすごい!
  • 71. Item 27: Familiarize yourself with alternatives to overloading on universal references. 覚えておくこと • ユニバーサルリファレンスとオーバーロードの組み合わせの代替案 には、異なる関数名を使用する、パラメータをconstへの左辺値参 照で渡す、パラメータを値で渡す、タグディスパッチを使う、が含まれ る。 • std::enable_if を通じてテンプレートを制約することで、ユニ バーサルリファレンスとオーバーロードを同時に使用できるが、それ はコンパイラがユニバーサルリファレンスのオーバーロードを使用す る条件を制御する。 • ユニバーサルリファレンスはたいてい効率上の利点があるが、概し て使い勝手の点で欠点もある。