是否有某种方法可以强制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;
}
我能做些什么(除了将f
的定义移到顶部之外),以便使代码编译并给出相同的结果,就像之前f
的所有定义都可用一样wrapper
的定义?
我找不到任何东西,可能是因为我不知道如何恰当地说出这个问题。如果有帮助,可以假定f
的所有参数类型都是用户定义的类型。
答案 0 :(得分:2)
是否有某种方法可以强制C ++编译器为a执行名称查找 在模板实例化期间(而不是之前)给出符号?
是。首先,名称必须依赖。 f
用作wrapper
时的名称f(t)
是依赖的,因为t
与类型有关。 [temp.dep] / 1:
表格形式:
后缀表达式
(
表达式列表 opt)
postfix-expression 是 unqualified-id , unqualified-id 表示依赖名称
- 表达式列表中的任何表达式都是包扩展(14.5.3),
- 表达式列表中的任何表达式都是依赖于类型的表达式(14.6.2.2),或
- 如果 unqualified-id 是 template-id ,其中任何模板参数都取决于模板参数。
问题是在模板本身之后声明的名称,即仅在实例化而不是定义上下文中,可以使用参数依赖名称查找单独找到。您的f
重载只接受基本类型,但根据[basic.lookup.argdep] / 2,它们没有与它们关联的全局命名空间:
如果
T
是基本类型,则其关联的命名空间集合和 课程都是空的。
因此,如果参数与参数的类型相同,则永远无法找到您声明的f
。一个小技巧可以帮助:
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
此模板在全局命名空间中声明时,将导致ADL考虑它。重写wrapper
如下:
template <class T>
auto wrapper( T t ) -> decltype( f( make_refwrap(t) ) )
{
return f( make_refwrap(t) );
}
Demo。这不是正确的方法,因为它会在更复杂的情况下失败。
答案 1 :(得分:1)
这适用于模板专业化。请注意,您必须确定默认函数是什么,因为我无法看到它的问题。
// default function
template <class T>
unsigned char f( T x ) { return x; }
// specialization for int
template <>
unsigned char f( int x ) { return x % 256; }
int main( int, char ** )
{
auto x = f( 3100 );
return 0;
}
答案 2 :(得分:0)
以下代码不是很干净,但说明了如何使用类模板特化来解决问题。它维护原始界面(即f
和wrapper
可以像以前一样使用。)
感谢您给我正确的提示。我愿意接受一个不那么冗长的解决方案。
#include <type_traits>
template <class ...>
struct F;
template <class T>
auto wrapper( T t )
-> decltype( F<typename std::decay<T>::type>::f( t ) )
{
return F<typename std::decay<T>::type>::f( t );
}
template <>
struct F<unsigned char>
{
static unsigned char f( unsigned char x ) { return x; }
};
template <>
struct F<int>
{
static unsigned char f( int x ) { return x % 256; }
};
template <class T>
auto f( T t )
-> decltype( F<typename std::decay<T>::type>::f( t ) )
{
return F<typename std::decay<T>::type>::f( t );
}
int main( int, char ** )
{
auto x = wrapper( 3100 );
return 0;
}