effective modern c++ 勉強会#7 item 27

71
Effective Modern C++ 勉強会#7 Item 27 刈谷 満(@kariya_mitsuru) 2015/6/17

Upload: mitsuru-kariya

Post on 23-Feb-2017

788 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: Effective Modern C++ 勉強会#7 Item 27

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

刈谷 満(@kariya_mitsuru)

2015/6/17

Page 2: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

ユニバーサルリファレンスを伴う

オーバーロードの代替案に

慣れ親しもう

Page 3: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

Item 26 で見たように、ユニバーサルリファレンスを伴うオーバーロードはヤバい

でも、オーバーロード便利(ただし、思った通りに動いてくれれば)

Page 4: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

こんな代替案がある

1. オーバーロードを諦める2. const T& で渡す3. 値で渡す4. タグディスパッチを使う5. ユニバーサルリファレンスをとるテンプレートに制約を設ける

Page 5: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

1.オーバーロードを諦める

そのまんま

オーバーロードするから訳が分からなくなる

オーバーロードしなきゃいんじゃね?

Page 6: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

これを

template<typename T>

void logAndAdd(T&& name);

void logAndAdd(int idx);

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

Item 27: Familiarize yourself with alternativesto 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);

Page 8: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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);

全て解決!

Page 9: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

欠点

コンストラクタには無力(コンストラクタには名前が無い)

本には名前固定って書いてあるけど、名前無いっすよ…

§12[class.ctor]/p.1 "Constructors do not have names."

てか、やっぱオーバーロード使いたくね?

Page 10: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

2.const T& で渡す

そのまんま

ユニバーサルリファレンス使うから訳がわからなくなる

ユニバーサルリファレンス使わなきゃいんじゃね?

Page 11: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

これを

template<typename T>

void logAndAdd(T&& name);

void logAndAdd(int idx);

Page 12: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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);

Page 13: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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);

全て解決!

Page 14: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

欠点

ユニバーサルリファレンス使う方法ほど効率的じゃない

(でもシンプルさは魅力的)

てか、やっぱユニバーサルリファレンス使いたくね?

Page 15: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

3.値で渡す

そのまんま

…え?効率は?

実はわりと効率がいい(場合も多い)

けど、詳細は Item 41 のお楽しみ

Page 16: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

これを

template<typename T>

explicit Person(T&& n)

: name(std::forward<T>(n)) {}

explicit Person(int idx)

: name(nameFromIdx(idx)) {}

Page 17: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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)) {}

Page 18: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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)) {}

全て解決!

Page 19: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

欠点この例ならわりと効率いいけど、

ユニバーサルリファレンスほどじゃないし、ムーブが効率悪い場合には使えない。(std::array とか…)

Item 41 を知らない人が見ると、「効率悪い!」と言われて、最悪直される(※ 個人の感想です)

0 はともかく、NULL を渡すと int バージョン呼ばれる。(けど、これに限らないし、Item 8 読め)

Page 20: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

4.タグディスパッチを使う

やっぱ完全転送したい!!!

みんな大好き、タグディスパッチ

Page 21: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

わあい

タグディスパッチめう

めうタグディスパッチ

大好きめう

©芽兎めう

Page 22: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

ユニバーサルリファレンスの問題点

あらゆる引数に完全一致する

Page 23: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

引数が

一つしかないと

錯覚していた?

©藍染惣右介

Page 24: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

解決策

ユニバーサルリファレンス以外の引数で、オーバーロード解決

を制御すれば良い

Page 25: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 を取るオーバーロードを追加したい

Page 26: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

logAndAdd のオーバーロードを追加するんじゃなくて、logAndAdd 内で実際に処理する関数logAndAddImpl に処理を委譲する

⇓この際、T が int の場合用と

そうじゃない場合用の関数を作って

それらの関数に追加の引数を追加して、

それらの型(タグ)が完璧に異なれば良い

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

Item 27: Familiarize yourself with alternativesto 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の時は「型②」

つまり、こんな感じにすれば良い

Page 28: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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の時は「型②」

つまり、こんな感じにすれば良い

で?「型①か型②」って?

Page 29: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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」から派生

Page 30: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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」から派生

でもちょっとうまくない…

Page 31: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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になっちゃう

Page 32: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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から「参照」を消す

Page 33: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 を呼び出す

Page 34: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 を呼び出す

賢いコンパイラなら、最後のパラメータ使ってないから

消してくれるかも…

こうすれば、ログ出力コード二重にメンテしなくて済む…

Page 35: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

タグディスパッチSUGEEEE!!!!

タグディスパッチのこと

もっと知りたい!!!

でも EMC++ にはそこまで書かれてない…

Page 36: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

そんなあなたに C++テンプレートテクニック 第2版

あのえぴさんとアキラさんが

書いてるぞ!!!

C++11完全対応!!!

電子書籍版もあるぞ!!!ちょっと読みづらいけど…

タグディスパッチだけじゃなくてテンプレート全般!!!

まだ全部理解できてないけど…

Page 37: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

タグディスパッチいいよ、タグディスパッチ

もう何もかもタグディスパッチでよくね?

Page 38: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

欠点

コンストラクタには無力

(またっすか…)

Page 39: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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コンストラクタ コピー

コンストラクタ

ムーブコンストラクタ

Page 40: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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);

全部完全転送…

上はいいけど、下に対してコピーコンストラクタが

呼ばれない…

Page 41: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

5.ユニバーサルリファレンスをとるテンプレートに制約を設ける

そのまんま

ユニバーサルリファレンスを取る関数が呼ばれて欲しくない時まで呼ばれちゃう

関数を呼ばれて欲しい時だけ有効にすればいんじゃね?

Page 42: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

「関数を呼ばれて欲しい時だけ有効に」?

そのためのメタ関数が type_traits に!

std::enable_if

SFINAE と呼ばれる機構を使ってる

Page 43: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 にする

Page 44: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

では、今回の場合、どんな時に呼ばれて欲しいのか?⇓

T が Person じゃない時T が Person の場合、コピーコンストラクタやムーブコンストラクタが呼ばれて欲しいから

そんな時も type_traits

Page 45: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

こんな式

!std::is_same<Person, T>::value

先頭の!に注意 Person と T が同じ型の時 true

型じゃなくてbool 値が欲しいから

::value

Page 46: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 が左辺値参照に…

Page 47: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

T と Person を比較する時には、以下の2点を無視したい

•参照かどうか引数の型が Person だろうが Person& だろうが Person&& だろうが、完全転送コンストラクタじゃ無くてコピー・ムーブコンストラクタが呼ばれてほしい

• const や volatile が付いているかどうか引数の型が const Person だろうが volatile Person だろうが const volatile Person だろうが、完全転送コンストラクタじゃ無k(以下略

そんな時も type_traits

Page 48: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

こんな式

!std::is_same<Person,

typename std::decay<T>::type

>::value

ホントはこれだと、配列や関数をポインタに変換しちゃうけど、今回の場合は問題なし

参照を取ってから、更に cv 修飾を取る!!

値じゃなくて型が欲しいから ::type

Page 49: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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&&

Page 50: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

完全転送コンストラクタは、

T が Person かその派生クラスの時には

無効化されて欲しい

そんな時も type_traits

Page 51: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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!

だいぶ長い…

Page 52: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 になるよ!

Page 53: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 は入らず…)

Page 54: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

でもまだ int を引数にとる

コンストラクタが追加されてない…

Page 55: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 でも超絶長い…

Page 56: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

SFINAE SUGEEEE!!!!

SFINAEのこと

もっと知りたい!!!

でも EMC++ にはそこまで書かれてない…

Page 57: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

そんなあなたに C++テンプレートテクニック 第2版

あのえぴさんとアキラさんが

書いてるぞ!!!

C++11完全対応!!!

電子書籍版もあるぞ!!!ちょっと読みづらいけど…

SFINAEだけじゃなくてテンプレート全般!!!

まだ全部理解できてないけど…

Page 58: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

トレードオフ

1. オーバーロードを諦める

2. const T& で渡す

3. 値で渡す

4. タグディスパッチを使う

5. ユニバーサルリファレンスをとるテンプレートに制約を設ける

完全転送を諦める(シンプル)

完全転送を使う(効率いい)

Page 59: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

完全転送の欠点

1.完全転送できない場合がある(完全じゃね~し… Item 30を参照)

2.クライアントが誤った引数を渡した時、とち狂ったエラーメッセージが出る

Page 60: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

とち狂ったメッセージの例

例えば、こんな感じに間違った場合…

Person p(u"Konrad Zuse");

巷で話題のutf-16 リテラル

Page 61: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 hereprog.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さん

Page 62: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 herePerson 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 argumentbasic_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 argumentbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_string(const basic_string& __str, size_type __pos, size_type __n = npos,^

Clangさん

Page 63: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

この例の場合、ユニバーサルリファレンスの引数は

std::string の初期化に使われることが分かっているので、

static_assert でチェックすることはできる。

Page 64: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 objectstatic_assert(

std::is_constructible<std::string, T>::value,"Parameter n can't be used to construct a std::string"

);

}

};

こんな感じでチェック!

Page 65: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 hereprog.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 providedprog.cc:19:3: error: static assertion failed: Parameter n can't be used to construct a std::string

static_assert(^

GCCさん

ここ!

Page 66: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 herePerson 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 argumentbasic_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 argumentbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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 providedbasic_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さん

ここ!

Page 67: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

でも、今回の例の場合、ホントはそもそも std::enable_if の条件にstd::is_constructible 使えばいいと

思うんだけど…

Errata には、コンパイラのエラーメッセージが、「そんなコンストラクタ無いよ」ってなるので、意味が変わっちゃうって書いてあるけど…

Page 68: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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)){…

}

};

こんな感じで無効化!

Page 69: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 'constPerson&'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さん

Page 70: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto 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 'constchar32_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 'constchar32_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 さんすごい!

Page 71: Effective Modern C++ 勉強会#7 Item 27

Item 27: Familiarize yourself with alternativesto overloading on universal references.

覚えておくこと• ユニバーサルリファレンスとオーバーロードの組み合わせの代替案には、異なる関数名を使用する、パラメータをconstへの左辺値参

照で渡す、パラメータを値で渡す、タグディスパッチを使う、が含まれる。

• std::enable_if を通じてテンプレートを制約することで、ユニ

バーサルリファレンスとオーバーロードを同時に使用できるが、それはコンパイラがユニバーサルリファレンスのオーバーロードを使用する条件を制御する。

• ユニバーサルリファレンスはたいてい効率上の利点があるが、概して使い勝手の点で欠点もある。