以下の関数test
は、左辺値の空の文字列、左辺値の空でない文字列、右辺値の文字列に対してオーバーロードされます。 ClangとGCCでコンパイルしようとしましたが、どちらの場合も期待した結果が得られません。
_#include <iostream>
void test(const char (&)[1]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <unsigned long int N>
void test(const char (&)[N]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
void test(char*&&){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main(){
char str1[] = "";
char str2[] = "test";
test("");
test("test");
test(str1);
test(str2);
}
_
Clangによる出力バージョン6.0.0-1ubuntu2:
_clang++ test.cpp -o test.out && ./test.out
void test(const char (&)[1])
void test(const char (&)[N]) [N = 5]
void test(char *&&)
void test(char *&&)
_
G ++での出力(MinGW.org GCC-8.2.0-3):
_g++ test.cpp -o test.exe && test.exe
test.cpp: In function 'int main()':
test.cpp:15:11: error: call of overloaded 'test(char [1])' is ambiguous
test(str1);
^
test.cpp:3:6: note: candidate: 'void test(const char (&)[1])'
void test(const char (&)[1]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
^~~~
test.cpp:6:6: note: candidate: 'void test(const char (&)[N]) [with long unsigned int N = 1]'
void test(const char (&)[N]){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
^~~~
test.cpp:8:6: note: candidate: 'void test(char*&&)'
void test(char*&&){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
^~~~
_
私の質問は:
test(str1)
とtest(str2)
が左辺値であるときに右辺値オーバーロードを選択するのはなぜですか?test(str1)
の呼び出しがあいまいなのはなぜですか?ありがとうございました。
- どのコンパイラが正しいですか?
GCCは正しいです。
- Clangでは、str1とstr2が左辺値であるのに右辺値のオーバーロードを選択するのはなぜですか?
Clangはtest(str1);
で間違っています。あいまいなはずです。 test(str2);
の場合、_str2
_は暗黙的にポインターに変換できます。つまり、配列からポインターへの減衰です。変換された_char*
_は右辺値です。 #3と同じ理由で、暗黙の変換シーケンスは同じランキングを持ち、非テンプレート関数が優先されます。 test(char*&&)
が選択されています。
- Gccでは、str1での呼び出しがあいまいなのはなぜですか。
test(const char (&)[1])
を呼び出すには、_char[1]
_から_const char[1]
_への修飾変換が必要です。 test(char*&&)
を呼び出すには、配列からポインタへの変換が必要です。どちらも 完全一致 として修飾され、同じランキングになります。
- この状況の標準ルールはありますか?
オーバーロード解決における暗黙的な変換シーケンスのランキング 、および 暗黙的な変換 を参照してください。
- 最後の2つの呼び出しを修正するにはどうすればよいですか?
それはあなたの意図に依存します。
文字列リテラルは右辺値ではありません。 ( → )
- 最後の2つの呼び出しを修正する方法は?
テンプレートの特殊化で すべてを明確化 できます。
#include <iostream>
template<typename C, std::size_t N>
void test(const C (&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(const C (&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C, std::size_t N>
void test(const C (&&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(const C (&&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C, std::size_t N>
void test(C (&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(C (&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C, std::size_t N>
void test(C (&&)[N]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename C>
void test(C (&&)[1]) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main(){
char str1[] = "";
char str2[] = "test";
test("");
test("test");
test(str1);
test(str2);
test(std::move(str1));
test(std::move(str2));
const char str3[] = "";
const char str4[] = "test";
test(std::move(str3));
test(std::move(str4));
}
与える
void test(const C(&)[1])[C = char付き]
void test(const C(&)[N])[with C = char;長い符号なし整数N = 5]
void test(C(&)[1])[with C = char]
void test(C(&)[N])[with C = char;長い符号なし整数N = 5]
void test(C(&&)[1])[with C = char]
void test(C(&&)[N])[with C = char;長い符号なし整数N = 5]
void test(const C(&&)[1])[with C = char]
void test(const C(&&)[N])[with C = char;長い符号なし整数N = 5]
@songyuanyaoの回答ありがとうございます。最後の2つのケースでtest(char*&&)
が選択された理由がわかりました。 @Darklighterの回答のおかげで、最初のオーバーロード時にテンプレートを特殊化してあいまいさを取り除くこともできました。
だから私は以下のような私の問題を解決しました:
#include <iostream>
template <unsigned long int N>
void test(const char (&)[N]){
std::cout << __PRETTY_FUNCTION__ << " //non-empty literal" << std::endl;
}
template <>
void test(const char (&)[1]){
std::cout << __PRETTY_FUNCTION__ << " //empty literal" << std::endl;
}
void test(char*&&){
std::cout << __PRETTY_FUNCTION__ << " //string variable" << std::endl;
}
int main(){
char str1[] = "";
char str2[] = "test";
test("");
test("test");
test(str1);
test(str2);
}
出力:
clang++ test.cpp -o test.out && ./test.out
void test(const char (&)[1]) //empty literal
void test(const char (&)[N]) [N = 5] //non-empty literal
void test(char *&&) //string variable
void test(char *&&) //string variable
g++ test.cpp -o test.exe && test.exe
void test(const char (&)[N]) [with long unsigned int N = 1] //empty literal
void test(const char (&)[N]) [with long unsigned int N = 5] //non-empty literal
void test(char*&&) //string variable
void test(char*&&) //string variable