我试图在命名空间中调用重载函数,并且有点挣扎。
工作示例1:无 namespace
class C {};
inline void overloaded(int) {}
template<typename T> void try_it(T value) {
overloaded(value);
}
inline void overloaded(C) {}
int main()
{
try_it(1);
C c;
try_it(c);
return 0;
}
工作示例2:在模板之前定义的所有重载
class C {};
namespace n {
inline void overloaded(int) {}
inline void overloaded(C) {}
}
template<typename T> void try_it(T value) {
n::overloaded(value);
}
int main()
{
try_it(1);
C c;
try_it(c);
return 0;
}
损坏的示例3:模板之后出现一些重载
class C {};
namespace n {
inline void overloaded(int) {}
}
template<typename T> void try_it(T value) {
n::overloaded(value);
}
namespace n {
inline void overloaded(C) {}
}
int main()
{
try_it(1);
C c;
try_it(c); // /tmp/test.cpp: In function ‘void try_it(T) [with T = C]’:
// /tmp/test.cpp:19:15: instantiated from here
// /tmp/test.cpp:8:7: error: cannot convert ‘C’ to ‘int’ for argument ‘1’ to ‘void n::overloaded(int)’
return 0;
}
为什么会这样呢?为了能够在模板函数之后声明或定义重载,我需要做什么?
最佳答案
这是从属名称查找的问题。
在overloaded(value);
表达式中,名称overloaded
是根据[temp.dep]/1依赖的。
据我所知,在表达式n::overloaded(value)
中,名称overloaded
(在id表达式n::overloaded
中)是,而不是依赖。
从属名称查找非常特殊,[temp.dep.res]/1
(在文件末尾有一个函数模板的实例化点,因此可以找到来自关联 namespace 的所有声明。)
对于非从属名称,将应用常规查找规则(从定义上下文中查找)。
因此,要查找在模板定义之后声明的名称,它们必须是依赖的,并可以通过ADL查找。
一个简单的解决方法是将另一个参数引入函数overloaded
或包装该参数,以使该函数的一个参数具有关联的命名空间n
:
#include <iostream>
class C {};
namespace n {
struct ADL_helper {};
inline void overloaded(int, ADL_helper = {})
{ std::cout << "n::overloaded(int,..)" << std::endl; }
}
template<typename T> void try_it(T value) {
overloaded(value, n::ADL_helper{});
}
namespace n {
inline void overloaded(C, ADL_helper = {})
{ std::cout << "n::overloaded(C,..)" << std::endl; }
}
int main()
{
try_it(1);
C c;
try_it(c);
}
或者:
namespace n {
template < typename T >
struct wrapper { T elem; };
inline void overloaded(wrapper<int>)
{ std::cout << "n::overloaded(wrapper<int>)" << std::endl; }
}
template<typename T> void try_it(T value) {
overloaded(n::wrapper<T>{value});
}
namespace n {
inline void overloaded(wrapper<C>)
{ std::cout << "n::overloaded(wrapper<C>)" << std::endl; }
}