初期化構文を使用しているときに変換演算子が呼び出されているのはなぜですか。また、CLANGエラーメッセージが間違っているように思われるのはなぜですか。
-
20-12-2019 - |
質問
私は次のコードを持っています。これは、明示的な変換コンストラクタを使用して1つのオブジェクトT2を構築します。これは、T1の暗黙の変換を実行します。これは予想され、第3版の第11.4.1項のC ++プログラミング言語で説明されています。
#include <iostream>
#include <string>
using namespace std;
class test1 {
public:
test1() {}
operator string() {
cout << "test1 string conversion operator called" << endl;
return string();
}
};
class test2 {
public:
test2() {}
test2(string s) {
cout << "test2 string conversion constructor called" << endl;
}
};
int main() {
test1 t1;
test2 t2(t1);
return 0;
}
.
そしてあなたが期待するように:
> clang++ --version
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.2
Thread model: posix
> clang++ -std=c++11 test.cc
> ./a.out
test1 string conversion operator called
test2 string conversion constructor called
.
しかし、T2の構造を初期化構文に変更する場合:
test1 t1;
test2 t2 = t1;
return 0;
.
CLANGは次のものを出力します。
test.cc:23:15: error: no viable conversion from 'test1' to 'test2'
test2 t2 = t1;
^ ~~
test.cc:13:11: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'test1' to 'const test2 &' for 1st argument
class test2 {
^
test.cc:13:11: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'test1' to 'test2 &&' for 1st argument
class test2 {
^
test.cc:16:9: note: candidate constructor not viable: no known conversion from 'test1' to 'string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') for 1st argument
test2(string s) {
^
test.cc:8:9: note: candidate function
operator string() {
^
1 error generated.
.
初期化がこのような暗黙の変換を実行できるようになったかどうかわかりませんが、エラーメッセージは非常に間違っているようです。 'test1'から 'string' への既知の変換はありません。候補関数演算子文字列(){
何が与えますか?また、C ++規格は、初期化コンストラクターでの暗黙の変換について何を言っていますか? i これが2つの暗黙の変換としてカウントされるべきであること、したがって許可されていないが、コンパイラの出力は全くそれを示唆していないことを想定しています。
解決
最初のオフでは、test2::test2(string)
を呼び出すことが間違っています「明示的な変換コンストラクタ」。暗黙の変換で使用されます(それを望まない場合はexplicit
マーク)。
とにかく、CLANGのエラーメッセージはスポットオンであり、それは何が起こっているのかほぼ完全に説明します。
これ:
test2 t2(t1);
.
は direct初期化と呼ばれます。test2
のすべてのコンストラクタは候補者と追加のコンポーネントで、コンパイラは引数と一致する暗黙の変換シーケンスを実行できます。test1::operator string
とtest2::test(string)
を見つけ、すべてが順調です。
これ:
test2 t2 = t1;
.
は copy initialization と呼ばれます。=
の右側の式をtest2
に変換する必要があり、コピーまたは移動コンストラクタが呼び出されてオブジェクトを構築する(少なくとも後に後で最適化として推測できるが、アクセス可能である必要があります)。それにもかかわらず)