Home > Enterprise >  In c can you separate the function called based on the template?
In c can you separate the function called based on the template?

Time:03-11

I have a function in C that works, in theory. What I mean by this, is if the function was converted to a language like Python, it would work just fine because it is not pre-compiled. However, in a language like C , it throws errors.

This is the function:

template <typename T>
T  JSONValue::get(){
    if(detect_number::detect<T> == true){
        if(type == JSONValueType::Number)
            return (T)number.value();
    }
    else if(detect_string::detect<T> == true){
        if(type == JSONValueType::String){return string.value();}
        return deparse(*this);
    }
    else if(detect_chararray::detect<T> == true){
        if(type == JSONValueType::String){return string.value().c_str();}
        std::string dep = deparse(*this);
        return dep.c_str();
    }
    else if(detect_boolean::detect<T> == true){
        if(!(type == JSONValueType::Boolean))
            return false;
        return boolean.value();
    }
    else if(is_specialization<T, std::vector>::value){
        if(type != JSONValueType::Array){
            std::cerr<<"must be an array to do this"<<std::endl;
            return T{};
        }
        T output;
        for(int i = 0; i < size(); i  ){
        output.push_back(array.value().at(i).get<std::decay<decltype(*output.begin())>::type>());   
        }
        return output;
    }
    return T(0);
}

In the if statements, it detects the type, T which is passed. If it is a number, do this, all through if it is a vector then do this.

The problem is, if a vector is put in as the template parameter, it throws an error because a number cannot be casted to a vector, and so on.

Is there a way to either get the compiler to ignore the error, or fix it so that the compiler does not have to ignore it and it will run?

I remember seeing something a while back that if the type is something in the typename, then run this function, otherwise run this other function.

CodePudding user response:

In C 17 and later, you can use if constexpr, eg:

if constexpr (detect_number::detect<T>){
    // T is a numeric type, do numerical things here...
}
else if constexpr (detect_string::detect<T>){
    // T is a string type, do stringy things here...
}
...

if statements are evaluated at runtime, so the entire function has to be syntaxically correct at compile-time, even though only parts of it will actually be used.

But, if constexpr statements are evaluated at compile-time instead. As such, any unused code blocks will be eliminated by the compiler and not evaluated at all. That will allow you use T in different ways in different if constexpr blocks. The compiler will treat your code as if you had written it more like this:

// only when T is a number
template <typename T>
T JSONValue::get(){
    if(type == JSONValueType::Number)
        return (T)number.value();
    }
    return T(0);
}

// only when T is a string
template <typename T>
T JSONValue::get(){
    if(type == JSONValueType::String){return string.value();}
    return deparse(*this);
}

...

Prior to C 17, you would have to use SFINAE or template specialization to accomplish the same thing, eg:

// SFINAE 

template <typename T,
    typename std::enable_if<detect_number::detect<T>, bool>::type = true
>
T JSONValue::get(){
    if(type == JSONValueType::Number)
        return (T)number.value();
    return T(0);
}

template <typename T,
    typename std::enable_if<detect_string::detect<T>, bool>::type = true
>
T JSONValue::get(){
    if(type == JSONValueType::String){return string.value();}
    return deparse(*this);
}

...
// specialization

template <typename T>
T JSONValue::get(){
    return T{};
}

template<>
int JSONValue::get<int>(){
    if(type == JSONValueType::Number)
        return (T)number.value();
    return T(0);
}

template<>
std::string JSONValue::get<std::string>(){
    if(type == JSONValueType::String){return string.value();}
    return deparse(*this);
}

...
  • Related