查看我的编译器创建的符号:
[tej@archivbox ~]$ cat test1.cc
#include <vector>
template<typename T>
auto JSchaubStackOverflow(T t) { return t.size(); }
// template<typename T>
// auto f(T t) { return t.foobar(); }
int do_something() {
JSchaubStackOverflow(std::vector<int>());
return 4;
}
[tej@archivbox ~]$ c++ -std=c++14 -pedantic test1.cc -c -o test1.o
[tej@archivbox ~]$ nm test1.o | grep JScha
0000000000000000 W _Z20JSchaubStackOverflowISt6vectorIiSaIiEEEDaT_
[tej@archivbox ~]$ nm -C test1.o | grep JScha
0000000000000000 W auto JSchaubStackOverflow<std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >)
[tej@archivbox ~]$ cat test2.cc
#include <vector>
template<typename T>
auto JSchaubStackOverflow(T t) -> decltype(t.size() /* plus some decay */) { return t.size(); }
template<typename T>
auto JSchaubStackOverflow(T t) -> decltype(t.foobar() /* plus some decay */) { return t.foobar(); }
struct Metallica
{
Metallica* foobar() const
{
return nullptr;
}
};
int do_something() {
JSchaubStackOverflow(std::vector<int>());
JSchaubStackOverflow(Metallica());
return 4;
}
[tej@archivbox ~]$ c++ -std=c++14 -pedantic test2.cc -c -o test2.o
[tej@archivbox ~]$ nm test2.o | grep JScha
0000000000000000 W _Z20JSchaubStackOverflowI9MetallicaEDTcldtfp_6foobarEET_
0000000000000000 W _Z20JSchaubStackOverflowISt6vectorIiSaIiEEEDTcldtfp_4sizeEET_
[tej@archivbox ~]$ nm -C test2.o | grep JScha
0000000000000000 W decltype (({parm#1}.foobar)()) JSchaubStackOverflow<Metallica>(Metallica)
0000000000000000 W decltype (({parm#1}.size)()) JSchaubStackOverflow<std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >)
从中可以看出,decltype(whatever) 可以帮助我们区分符号,它是签名的一部分。但是“auto”对我们没有帮助......因此,如果 vector 同时具有 foobar 和 size 方法,则 JSchaubStackOverflow 的两个重载都将被损坏为Z20JSchaubStackOverflowISt6vectorIiSaIiEEEDaT
现在我将留给其他人查找 ISO 中有关签名的相关部分的模板函数。
--EDIT-- 我知道它已经有一个公认的答案,但为了记录,这里有一个技术难题——没有定义的声明:
[tej@archivbox ~]$ cat test2.cc
#include <vector>
template<typename T>
auto JSchaubStackOverflow(T t) -> decltype(t.size());
template<typename T>
auto JSchaubStackOverflow(T t) -> decltype(t.foobar());
struct Metallica
{
Metallica* foobar() const
{
return nullptr;
}
};
int do_something() {
JSchaubStackOverflow(std::vector<int>());
JSchaubStackOverflow(Metallica());
return 4;
}
[tej@archivbox ~]$ c++ -std=c++14 -pedantic test2.cc -c -o test2.o
[tej@archivbox ~]$ nm -C test2.o | grep JScha
U decltype (({parm#1}.foobar)()) JSchaubStackOverflow<Metallica>(Metallica)
U decltype (({parm#1}.size)()) JSchaubStackOverflow<std::vector<int, std::allocator<int> > >(std::vector<int, std::allocator<int> >)
这意味着一个人可以在没有函数体的情况下完成整个事情。模板特化将在另一个翻译单元中给出,但为此,链接器需要找到它们......因此不能在函数体上重载。