pass name lookup in template function
Is there some way to force C++ compilers to perform name lookup for a given symbol during template instantiation (and not before)?
Given the following code:
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;
}
Is there anything I can do (apart from moving the definition of f
to the top) in order to make that code compile and give the same results as if all definitions of f
were available before the definition of wrapper
?
I could not find anything, probably because I do not know how to phrase this question properly. All argument types of f
can be assumed to be user-defined types, if this helps.
Is there some way to force C++ compilers to perform name lookup for a given symbol during template instantiation (and not before)?
Yes. First of all, the name must be dependent. The name f
in wrapper
when used as f(t)
is dependent because t
is type-dependent. [temp.dep]/1:
In an expression of the form:
postfix-expression (
expression-list opt )
where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if
The problem is that names declared after the template itself, ie only in the instantiation but not the definition context, can solely be found using argument dependent name lookup . Your f
overloads only take fundamental types, but those do not have the global namespace associated with them according to [basic.lookup.argdep]/2:
If T
is a fundamental type, its associated sets of namespaces and classes are both empty.
Thus the f
s you declared can never be found if the arguments are of the same type as the parameters. A little trick can help:
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
This template, when declared in the global namespace, will cause ADL to consider it. Rewrite wrapper
as follows:
template <class T>
auto wrapper( T t ) -> decltype( f( make_refwrap(t) ) )
{
return f( make_refwrap(t) );
}
Demo . This is not the proper way to do it though, as it will fail in more complex scenarios.
This would work with template specialization. Note that you have to decide what the default function is, because i cannot see it in question.
// 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;
}
The following code is not quite clean, but illustrates how class template specialization can be used in order to solve the problem. It maintains the original interface (ie f
and wrapper
can be used in the same way as before).
Thank you for giving me the right hints. I am open for a solution that is less verbose though.
#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;
}
链接地址: http://www.djcxy.com/p/24488.html
上一篇: 一个匿名类可以实现抽象类的非抽象方法吗?
下一篇: 在模板函数中传递名称查找