は、次のクラスを考えてみましょう:もちろんこの場合、最も適切なコンストラクタが呼び出されないのはなぜですか?
class foo {
int data;
public:
template <typename T, typename = enable_if_t<is_constructible<int, T>::value>>
foo(const T& i) : data{ i } { cout << "Value copy ctor" << endl; }
template <typename T, typename = enable_if_t<is_constructible<int, T>::value>>
foo(T&& i) : data{ i } { cout << "Value move ctor" << endl; }
foo(const foo& other) : data{ other.data } { cout << "Copy ctor" << endl; }
foo(foo&& other) : data{ other.data } { cout << "Move ctor" << endl; }
operator int() { cout << "Operator int()" << endl; return data; }
};
それは参照の任意の種類によって単一int
を取るためにあまり意味がありませんが、これはあくまでも一例です。 data
メンバは、コピーするのに非常にコストがかかる可能性があります。したがって、すべての移動セマンティクス。
このファンシーテンプレートは、基本的にdata
を構築できるあらゆるタイプを可能にします。したがって、foo
オブジェクトは、この基準を満たす任意の型の値をコピーまたは移動するか、単にタイプfoo
の別のオブジェクトをコピーまたは移動することによって構築することができます。今のところかなりまっすぐです。あなたはこのような何かをしようとすると、
問題が発生します。
foo obj1(42);
foo obj2(obj1);
このが(私の意見ではLESTで)やるべきこと(これに値42を移動することで最初のオブジェクトを構築することですそれはrvalueなので)、最初のオブジェクトをコピーして2番目のオブジェクトを構築します。だから、これはプリントアウトしなければならないものです。
Value move ctor
Copy ctor
をしかし、それは実際にプリントアウトすることです:
Value move ctor
Operator int
Value move ctor
第一の目的はそこに、何の問題をうまく構築されていないされます。しかし、コピーコンストラクタを呼び出して第2のオブジェクトを構築する代わりに、プログラムは最初のオブジェクトを別の型に変換してから、その型から移動できるfoo
という別のコンストラクタを呼び出します(その時点のrvalueです)。 )。
これは非常に奇妙なことですが、このコードからはっきりとした動作ではありません。コピーコンストラクタを2番目のオブジェクトの作成時に呼び出す方が理にかなっていると思います。
ここで何が起こるか説明できますか?もちろん、私はintへのユーザ定義の変換があるので、これは完全に有効なパスですが、私はそれを理解できません。なぜコンパイラは、指定された値とまったく同じ引数型を持つコンストラクタを単に呼び出すことを拒否しますか?それが最も簡単なことではないでしょうか?したがって、デフォルトの動作ですか?変換演算子を呼び出すとコピーも実行されるので、単にコピーコンストラクターを呼び出すよりも速く、最適ではないと思います。
現在のようにis_constructibleではなく、代わりにではありませんか? –
Alejandro
@Alejandro Correct、それも[問題を解決する](https://ideone.com/6SRrGr)です。 – nwp
@nwp私は混乱しています。 [this](http://en.cppreference.com/w/cpp/types/is_constructible)によると、そのことは、**拳のこと**が第2のものから構築できるかどうかを返します**。そして 'T'引数から' data'メンバ( 'int')を構築しているので、これは正しい順序でなければなりません。私は 'int'を構築できる型しか受け入れません。 – adam10603