I am working on a generic utility for use in translating symbolic integer constants to strings and vice versa. I am running into an issue with a helper template to optimize the passing of the string parameter. The reason for this template is that I want to allow the user to pass both a char_t* and string_t (char_t is simply a typedef for char currently, and string_t is a typedef of std::basic_string). Since a char* is a primitive type it is best passed by value, and since std::basic_string<> is a complex type it is best passed by reference. The template optimize_insert has a dual purpose to not allow the user to pass anything other than a (const) char_t* or a (const) string_t& but also to ensure that they are passed in the most efficient manner possible.
My understanding of template argument deduction, which I think is where I am running into an issue, is only rudimentary. But as far as I have been able to tell from google searching and reading of the standard N3690 this template should be able to be automatically deduced without having to explicitly write insert<int_t, string_t>(...)
.
Does anyone know of why clang would be failing to to infer the type of the template argument string_type. The exact error message is "candidate template ignored: couldn't infer template argument 'string_type'".
The code is as follows:
template <typename enum_backing_type>
struct enum_map
{
typedef map_t<int_t, string_t>::type etos_type;
typedef map_t<shash_t, int_t>::type stoe_type;
};
template <typename check_type>
struct optimize_insert;
template <>
struct optimize_insert<string_t>
{
typedef const string_t& type;
};
template <>
struct optimize_insert<char_t*>
{
typedef const char_t* type;
};
template <typename enum_backing_type, typename string_type>
bool_t insert(typename enum_map<enum_backing_type>::etos_type inMap,
enum_backing_type inKey,
typename optimize_insert<string_type>::type inValue)
{
/* see if the entry already exists */
typename enum_map<enum_backing_type>::etos_type::iterator findIter;
/* is there a difference between using std::find and std::map.find()? */
findIter = std::find(inMap.begin(), inMap.end(), inKey);
if (findIter != inMap.end())
return false_t;
/* make pair and insert */
std::pair<enum_backing_type, string_t> entry;
entry = std::make_pair(inKey, string_t(inValue));
inMap.insert(entry);
return true_t;
}
The calling code is as follows:
enum eTest : schar_t
{
kTest_1,
kTest_2,
kTest_3
};
int main(int argc, char* argv[])
{
enum_map<schar_t>::etos_type etos_map;
enum_map<schar_t>::stoe_type stoe_map;
/* test const char_t* */
insert(etos_map, kTest_1, "kTest_1");
/* test string_t */
string_t test2_string("kTest_2");
insert(etos_map, kTest_2, test2_string);
/* following statement should fail to compile */
insert(etos_map, kTest_2, 1);
for (enum_map<schar_t>::etos_type::iterator printIter = etos_map.begin();
printIter != etos_map.end();
++printIter)
{
std::cout << printIter->second << std::endl;
}
return 0;
}
Edit: So it seems this is a non-deducible case and I simply did not research into this enough to find the answer (sorry about that). Does anyone know of how to overcome this limitation such that there can be a version of the template for string_t and const char_t* that passes the parameters in the most efficient manner and without having to duplicate code and do some scheme where the const char_t* version would simply construct a string_t and pass it to the first function?