I'm refactoring some Windows code and I stumbled upon a problem I wanted to see if C++ templates could solve. I want to alter the type used by the function and append a suffix to the function's name (identifier). Note the template name doesn't change, but the instantiated name of the function seen by the linker is what changes.
Since C++ templates normally involve creating overloads of a function whose name does not change, I want to additionally change the name of the function seen by the linker. When calling this function, the portion of the function name will be passed along with the other template parameters. Let me start with a classic example which I will build upon:
template <class DataType>
size_t alterMyString(DataType* s)
{
...
}
//somewhere later - call Wide version of function here.
// function signature: size_t alterMyString(WCHAR* s)
alterMyString<WCHAR>(s);
So far so good. Now, let's say I want the generated function to be alterMyStringWide so that, I may even forward declare the final prototype somewhere else and have callers sync up with the templatized implementation without having to know how it was implemented. I thought this sounds cool in theory!
size_t alterMyStringWide(WCHAR* s);
Here's a way one might attempt to code this, although the use of a preprocessor MACRO is clearly wrong as it would occur before template expansion not to mention gluing strings together with ## when I'm not dealing with strings but rather an identifier. This snippet still shows the gist of what I'm trying to do: gluing an identifier together during template expansion.
//obviously won't compile
#define DECLARE_FUNC_NAME(base,suffix) base##suffix
template <class DataType, class FuncSuffix>
size_t DECLARE_FUNC_NAME(alterMyString,FuncSuffix)(DataType* s)
{
...
}
//can I get this signature: size_t alterMyStringWide(WCHAR* s)
// from a template instantiation like this?
alterMyString<WCHAR,Wide>(s);
Is this possible in any C++ [template] standard? I'm coming up empty when I search if something like this is even possible. I'm not a C++ template guru, so forgive me if there is better terminology for what I'm asking.
A workaround I've come up with involves creating an outer function whose name is what I want, but is internally implemented using a template:
//plain old template
template <class DataType>
size_t tpl_alterMyString(DataType* s)
{
...
}
//this works - I can also forward declare this function prototype and callers
// don't need to know or care whether how it was implemented
size_t alterMyStringWide(WCHAR* s)
{
return(tpl_alterMyString<WCHAR>(s));
}
While the code above works as intended, can it be simplified to remove the outer function such that the final function identifier can be parameterized with the rest of the template arguments?
EDIT: For what its worth, this is an exercise for educational purposes only and not part of any production code. Because this question does not fit into the standard paradigm of how C++ templates are typically used (i.e. function overload generators), this is what prompted me to ask the question here on StackOverflow. Hate on me if you must, but I disagree that the question as proposed is necessarily an implication of bad design. :)
With that said, I understand the benefits of overloads and not having to explicitly call out a special version of a function by relying on slightly different names. There exists much literature on this topic spanning decades and I don't disagree with that paradigm.
But, if one thinks outside of that paradigm for a moment, this doesn't invalidate use cases where you might want the generated function to have a dynamic name. Templates are glorified text-substitution mechanisms by their very nature so I don't think my suggestion is crazy or necessarily contrary to a Best Practice.
In my example, the template is an implementation detail, and nothing more. I know ahead of time which instantiations I want to support; I might not want users calling my template implementation directly with template syntax because I might want my functions to support being called from both C and C++ translation units. Another thing I gain is not having to distribute the implementation; and, at the same time I can still leverage the power of C++ templates to automate the creation of these similar functions.