Mar*_*ayr 7 c++ templates name-lookup
有没有办法迫使C++编译器在模板实例化期间(而不是之前)对给定符号执行名称查找?
给出以下代码:
template <class T>
auto wrapper( T t ) -> decltype( f( t ) )
{
return f( t );
}
unsigned char f( int x ) { return x % 256; }
unsigned char f( unsigned char x ) { return x; }
int main( int, char ** )
{
auto x = wrapper( 3100 );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有什么我可以做的(除了将定义f移到顶部),以便使代码编译并给出相同的结果,好像所有定义f在定义之前都可用wrapper?
我找不到任何东西,可能是因为我不知道如何恰当地说出这个问题.f如果有帮助,可以假设所有参数类型都是用户定义的类型.
是否有某种方法可以强制 C++ 编译器在模板实例化期间(而不是之前)执行给定符号的名称查找?
是的。首先,名字必须是依赖的。用作时f的名称是相关的,因为它是类型相关的。[温度.dep]/1:wrapperf(t)t
在以下形式的表达式中:
后缀表达式
(表达式列表 opt)其中后缀表达式是unqualified-id,则 unqualified-id表示依赖名称,如果
- 表达式列表中的任何表达式都是包扩展 (14.5.3),
- 表达式列表中的任何表达式都是类型相关的表达式 (14.6.2.2),或
- 如果unqualified-id是一个template-id,其中任何模板参数都依赖于模板参数。
问题在于,在模板本身之后声明的名称(即仅在实例化中而不是在定义上下文中)只能使用参数相关名称查找来找到。您的f重载仅采用基本类型,但根据 [basic.lookup.argdep]/2,这些重载没有与之关联的全局命名空间:
如果
T是基本类型,则其关联的命名空间和类集都是空的。
因此,f如果参数与形参的类型相同,则永远找不到您声明的 s。一个小技巧可以帮助您:
template <typename T>
struct refwrap
{
T&& t;
refwrap(T&& t) : t(std::forward<T>(t)) {}
operator T&&() {return std::forward<T>(t);}
};
template <typename T>
auto make_refwrap( T&& t ) -> refwrap<T> // making use of reference collapsing
{ return {std::forward<T>(t)}; } // inside refwrap to get forwarding
Run Code Online (Sandbox Code Playgroud)
当在全局命名空间中声明此模板时,ADL 会考虑它。重写wrapper如下:
template <class T>
auto wrapper( T t ) -> decltype( f( make_refwrap(t) ) )
{
return f( make_refwrap(t) );
}
Run Code Online (Sandbox Code Playgroud)
演示。但这不是正确的方法,因为在更复杂的情况下它会失败。