1

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?

teddy
  • 171
  • 1
  • 1
  • 12
  • 1
    Please include the actual *call* that is passing arguments failing to deduce the template param types, along with appropriate declarations of those arguments. – WhozCraig Jul 11 '14 at 12:23
  • See the following questions: [C++, template argument can not be deduced](http://stackoverflow.com/questions/6060824/c-template-argument-can-not-be-deduced) and [Why is the template argument deduction not working here?](http://stackoverflow.com/questions/1268504/why-is-the-template-argument-deduction-not-working-here). – Constructor Jul 11 '14 at 12:25
  • to Constructor: I looked at both those questions previously neither apply to the specific case that I am looking at. Which involves using a helper template to modify the type of the parameter being passed. to WhozCraig: I added the calling code. – teddy Jul 11 '14 at 12:29
  • 1
    The problem is exactly the same as in those two questions: In `X::type`, `T` is a non-deduced context. Which means the compiler won't even try to deduce `T` / `string_t` based on that argument. – aschepler Jul 11 '14 at 12:32
  • *is there a difference between using std::find and std::map.find()?* - I think the same reasoning applies as for `std::begin` and `std::end`. See here: [here](http://stackoverflow.com/a/8452194/1174378) – Mihai Todor Jul 11 '14 at 12:35
  • to Mihai Todor: thanks for that forgot I had that comment to myself in there XD. That was a note for myself to look that up later actually. to the others: okay so I guess that the compiler cannot deduce it. So perhaps maybe a better question would be does someone know of a method for doing what I am trying to do without the use of overloading since template functions cannot be overloaded? – teddy Jul 11 '14 at 12:40
  • What do you mean when you say that function templates cannot be overloaded? – Constructor Jul 11 '14 at 12:43
  • I was under the impression that if you try to do a function `template void foo(T first, int second)` and `template void foo(T first, double second)` would fail to compile as a redefinition of the same template. Or at least the last time I checked it failed to compile. – teddy Jul 11 '14 at 12:45
  • [Check once again.](http://coliru.stacked-crooked.com/a/362931e3cedcc402) – Constructor Jul 11 '14 at 12:51
  • Thanks again Constructor. Guess I should have checked that before I posted. Seems that that issue was resolved since the last time I checked. So it seems if I can use overloading I will have to forward the const char* call to the string version to achieve the effect I am looking for. Is there some mechanism for closing this as resolved? I am still fairly new to stack overflow. And sorry about the issues with the post. It seems that I needed to look into this further and read a bit deeper to find the answer. Sorry that I wasted your time. – teddy Jul 11 '14 at 13:03
  • You can try to answer to your own question and accept this answer (or try to wait for someone do it for you). But it seems that your question simply will be closed as a duplicate later. – Constructor Jul 11 '14 at 13:09
  • How would I go about closing it as a duplicate? – teddy Jul 11 '14 at 13:11
  • Or is it possible to simply delete the post? – teddy Jul 11 '14 at 13:12
  • Press `flag` button under your question and mark `it is a duplicate...`. It is possible to delete it but are you really want to do it? – Constructor Jul 11 '14 at 13:19

0 Answers0