Dark Sorrow
Dark Sorrow

Reputation: 1937

Template Conflict between String and Int

I have a program that creates a JSON file using json-glib for ReST Server. The file has 2 field namely id and value. id is only std::string but value can be an integer, a boolean, a string (through std::string od char const *) or a floating point, depending on the value to be transmitted. I have trouble in c.str() function and char *.

if(std::is_integral<T>::value)
        {
            if(std::is_same<T, bool>::value)
            {
                if(json_builder_add_boolean_value (builder, tagValue) == nullptr)
                {
                    returnMessage = string("json_builder_add_boolean_value was inconsistent in setTag(Boolean). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
                   cerr << returnMessage;
    #endif 
                    return false;
                }
            }
            else
            {
                if(json_builder_add_int_value (builder, tagValue) == nullptr)
                {
                    returnMessage = string("json_builder_add_int_value was inconsistent in setTag(Int). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
                   cerr << returnMessage;
    #endif 
                    return false;
                }
            }
        }
        else if(std::is_floating_point<T>::value)
        {
            if(json_builder_add_double_value (builder, tagValue) == nullptr)
            {
                returnMessage = string("json_builder_add_double_value was inconsistent in setTag(Double). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
               cerr << returnMessage;
    #endif 
                return false;
            }
        }
        else if(std::is_same<T, string>::value or std::is_same<T, const string>::value)
        {
            if(json_builder_add_string_value (builder, tagValue.c_str()) == nullptr)
            {
                returnMessage = string("json_builder_add_string_value was inconsistent in setTag(String). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
               cerr << returnMessage;
    #endif 
                return false;
            }
        }
        else if(std::is_same<T, char *>::value or std::is_same<T, const char *>::value)
        {
            if(json_builder_add_string_value (builder, tagValue) == nullptr)
            {
                returnMessage = string("json_builder_add_string_value was inconsistent in setTag(String). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
               cerr << returnMessage;
    #endif 
                return false;
            }


}

error: request for member ‘c_str’ in ‘tagValue’, which is of non-class type ‘int’ if(json_builder_add_string_value (builder, tagValue.c_str()) == nullptr)

error: invalid conversion from ‘int’ to ‘const gchar* {aka const char*}’ [-fpermissive]

Upvotes: 3

Views: 195

Answers (1)

max66
max66

Reputation: 66230

I'm using C++14

It's a pity. You can't use if constexpr that is the natural solution for your problem but it's introduced from C++17.

Anyway, without if constexpr, the compiler must compile every part of your function; so if your tagValue is a bool, the compiler must compile also the tagValue.c_str() call that isn't available for a bool.

So the error.

Pre C++17 you have to develop different function for different types.

A possible solution is use overloading and SFINAE defining three not-template foo() functions for the three exact types (bool, std::string const & and char const *)

void foo (std::string const & id, bool value)
 {
   // json_builder_add_boolean_value, etc

   std::cout << "-- bool case: " << id << ", " << value << std::endl;
 }

void foo (std::string const & id, std::string const & value)
 {
   // json_builder_add_string_value, etc

   std::cout << "-- std::string case: " << id << ", " << value << std::endl;
 }

void foo (std::string const & id, char const * value)
 {
   // json_builder_add_string_value, etc

   std::cout << "-- char * case: " << id << ", " << value << std::endl;
 }

and two template foo() functions, enabled through SFINAE for integral types (the first one) and for floating point types (the second one)

template <typename T>
std::enable_if_t<std::is_integral<T>{}>
   foo (std::string const & id, T const & value)
 {
   // json_builder_add_int_value, etc

   std::cout << "-- integral case: " << id << ", " << value << std::endl;
 }

template <typename T>
std::enable_if_t<std::is_floating_point<T>{}>
   foo (std::string const & id, T const & value)
 {
   // json_builder_add_double_value, etc

   std::cout << "-- floating case: " << id << ", " << value << std::endl;
 }

so calling

   foo("1", false);
   foo("2", 0L);
   foo("3", 0.0f);
   foo("4", std::string{"zero"});
   foo("5", "zero");

you get

-- bool case: 1, 0
-- integral case: 2, 0
-- floating case: 3, 0
-- std::string case: 4, zero
-- char * case: 5, zero

Observe that bool is an integral type, so can match the foo() template integral version and the foo() bool specific version.

In this case is preferred the exact match, so the bool specific version is called.

Upvotes: 1

Related Questions