字符串文本左值和右值引用的函数重载



下面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; }
^~~~

我的问题是:

  1. 哪个编译器是正确的?
  2. 有了 Clang,为什么test(str1)test(str2)选择右值重载而它们是左值?
  3. 对于 GCC,为什么调用test(str1)模棱两可?
  4. 这种情况有标准规则吗?
  5. 如何解决最后两个电话?

谢谢。

  1. 哪个编译器是正确的?

海湾合作委员会是正确的。

  1. 对于 clang,为什么 str1 和 str2 在它们是左值时选择右值重载?

叮当在test(str1);上错了,应该是模棱两可的。对于test(str2);str2可以隐式转换为指针,即数组到指针衰减。转换后的char*是一个右值。出于与#3相同的原因,隐式转换序列具有相同的排名,则首选非模板函数;test(char*&&)处于选中状态。

  1. 有了 gcc,为什么用 str1 调用是模棱两可的?

对于要调用的test(const char (&)[1]),需要从char[1]const char[1]的限定转换;要调用test(char*&&),需要数组到指针的转换。两者都有资格作为完全匹配并具有相同的排名。

  1. 这种情况有标准规则吗?

请参阅重载分辨率和隐式转换中隐式转换序列的排名。

  1. 如何修复最后两个调用?

这取决于您的意图。

字符串文本不是右值。(→(

  1. 如何修复最后两个调用?

您可以使用模板专用化消除所有内容的歧义:

#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]( [with C = char]void test(const C (&([N]( [with C = char; long unsigned int N = 5]void test(C (&([1]( [with C = char]void test(C (&([N]( [with C = char; long unsigned int N = 5]void test(C (&&([1]( [with C = char]void test(C (&&([N]( [with C =






char; long unsigned int N = 5]void test(const C (&&([1]( [with C (&&([
1]( [withC = char]void test(const C (&&([N]( [C = char; long unsigned int N = 5]

谢谢你@songyuanyao你的回答,我现在明白为什么在最后两种情况下选择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

相关内容

  • 没有找到相关文章

最新更新