以下代码编译得很好:(没有命名空间)
#include <vector>
template <class T>
void foo(const int & from, std::vector<T> & to)
{
for (int i = 0; i < 5; i++)
{
T bar;
foo(from, bar);
to.push_back(bar);
}
}
struct Bar
{
int a;
int b;
};
struct Baz
{
std::vector<Bar> bars;
};
void foo(const int & from, Bar & to)
{
to.a = from;
to.b = from - 1;
}
void foo(const int & from, Baz & to)
{
foo(from, to.bars);
}
void fooTest()
{
int num = 10;
Baz baz;
foo(num, baz);
}
int main()
{
fooTest();
}
但是当我为Bar和Baz引入命名空间时,它无法编译. (带命名空间)
#include <vector>
template <class T>
void foo(const int & from, std::vector<T> & to)
{
for (int i = 0; i < 5; i++)
{
T bar;
foo(from, bar);
to.push_back(bar);
}
}
// When I add this namespace, it fails to compile
namespace BarBar
{
struct Bar
{
int a;
int b;
};
struct Baz
{
std::vector<Bar> bars;
};
}
void foo(const int & from, BarBar::Bar & to)
{
to.a = from;
to.b = from - 1;
}
void foo(const int & from, BarBar::Baz & to)
{
foo(from, to.bars);
}
void fooTest()
{
int num = 10;
BarBar::Baz baz;
foo(num, baz);
}
int main()
{
fooTest();
}
它显示错误:
with_namespace.cpp: In instantiation of ‘void foo(const int&, std::vector<T>&) [with T = BarBar::Bar]’:
with_namespace.cpp:37:22: required from here
with_namespace.cpp:9:12: error: no matching function for call to ‘foo(const int&, BarBar::Bar&)’
foo(from, bar);
^
with_namespace.cpp:4:6: note: candidate: template<class T> void foo(const int&, std::vector<T>&)
void foo(const int & from, std::vector<T> & to)
^
with_namespace.cpp:4:6: note: template argument deduction/substitution failed:
with_namespace.cpp:9:12: note: ‘BarBar::Bar’ is not derived from ‘std::vector<T>’
foo(from, bar);
^
另请注意,使用MSVC时,带命名空间的代码编译得很好.为什么编译器在使用命名空间时找不到定义?
我使用以下版本:g(Ubuntu 5.4.0-6ubuntu1~16.04.9)5.4.0 20160609
更新:
在@ M.M指出函数查找如何为模板和ADL工作之后,我进行了以下修复:
#include <vector>
template <class T>
void foo(const int & from, std::vector<T> & to)
{
for (int i = 0; i < 5; i++)
{
T bar;
foo(from, bar);
to.push_back(bar);
}
}
namespace BarBar
{
struct Bar
{
int a;
int b;
};
struct Baz
{
std::vector<Bar> bars;
};
};
// Put them in the same namespace as Bar so that the templated foo find this function
namespace BarBar
{
using ::foo; // We are going to use templated foo in the latter functions
void foo(const int & from, BarBar::Bar & to)
{
to.a = from;
to.b = from - 1;
}
void foo(const int & from, BarBar::Baz & to)
{
foo(from, to.bars);
}
}
void fooTest()
{
int num = 10;
BarBar::Baz baz;
BarBar::foo(num, baz);
}
int main()
{
fooTest();
}
最佳答案 在代码中:
template <class T>
void foo(const int & from, std::vector<T> & to)
{
T bar;
foo(from, bar);
名称栏依赖于类型,因为其类型取决于模板参数.此外,名称foo(在foo(from,bar)中)是一个从属名称,因为其中一个函数调用参数是类型相关的. (C 17 [temp.dep] / 1).
依赖名称的名称查找工作方式如下(C 17 [temp.dep.res] / 1):
In resolving dependent names, names from the following sources are considered:
- Declarations that are visible at the point of definition of the template.
- Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context
第二个项目符号点称为ADL(依赖于参数的查找).
在你的第二个代码中,查找依赖foo什么都找不到:
>在模板的位置没有其他可见的定义
> int和T(BarBar :: Bar)的关联命名空间是:BarBar,没有名称BarBar :: foo.
在第一个代码中,查找依赖的foo:int和:: Bar的关联命名空间是:全局命名空间.全局命名空间中有:: foo,因此ADL可以找到它.
要修复第二个代码,您应该将后面带有BarBar ::参数的foo定义移到名称空间BarBar中. (在这种情况下,您还需要在第37行使用:: foo来查找模板foo).