Variadic template function name lookup fails to find specializations
I am attempting to program a string concatenation function which utilizes my 3D library's string conversion functions, implemented with a variadic template.
The library's conversion function behaves unusually if a string (either const char[] literal or std::string) is passed to it. as it does not actually possess functions for those types, so I want to specialize the template to pull those out and not run them through the converter. Optimization would be a good reason even if the converter handled them.
template<typename T>
inline String c(T a)
{
return Ogre::StringConverter::toString( a );
}
template<>
inline String c(String s)
{
return s;
}
template<>
inline String c(const char s[])
{
return s;
}
template<typename T, typename... Args>
inline String c(T a, Args... args)
{
return Ogre::StringConverter::toString( a ) + c(args...);
}
template<typename... Args>
inline String c(String s, Args... args)
{
return s + c(args...);
}
template<typename... Args>
inline String c( const char s[], Args... args)
{
return s + c(args...);
}
However, when I compile my program, string literals sometimes fall through the const char[] specialization and are handled by the base, unspecialized template. The command:
U::c( "This is dMap[500][500]: ", dMap[500][500], " and this is 5: ", 5, "." )
returns
This is dMap[500][500]: 112true5.
"true" being what toString returns if a string literal is passed to it. Debugging confirms that the second string literal is caught by the generic String c(T a, Args... args)
, but not the first or third, which are handled by the specialization.
This seems related to the problem mentioned in Selecting string literal type for template specialization, but changing my template parameter declaration match those suggested in that solution, inline String c( const char (&s) [N], Args... args )
, cause the first parameter to be caught by the specialized template, but not the second or third. Something unusual is happening here and I cannot figure out what it is.
In
template<typename T, typename... Args>
inline String c(T a, Args... args)
{
return Ogre::StringConverter::toString( a ) + c(args...);
}
unqualified name lookup for c
in c(args...)
is performed in the template definition context, which means that it only finds overloads of c
declared up to this point, and will not find your later c
overloads. (ADL is performed using both the definition and the instantiation contexts, but in your case it looks like there's no ADL.)
Declare them all first:
template<typename T, typename... Args>
inline String c(T a, Args... args);
template<typename... Args>
inline String c(String s, Args... args);
template<typename... Args>
inline String c( const char s[], Args... args);
before you define them, so that all three overloads can be found.
Incidentally, you should not use specializations for the single-argument case. Delete the template<>
and use overloads instead. As written right now, U::c("");
will not behave the way you want it to.
Demo.
链接地址: http://www.djcxy.com/p/62164.html上一篇: 将位图保存到位置
下一篇: 可变模板函数名称查找无法找到专业化