Question

I am trying to write something along the following lines:

void setData<T>(char * environmentVariable, T &data, T defaultValue)
{
    bool ret = false;
    // Try to get the environmentVariable
    ret = handle.getParam(environmentVariable, data);
    if(!ret)
    {
        data = defaultValue
    }
}

int main()
{
    int valOne;
    float valTwo;

    // Get a value of type int
    setData("some_int_value", valOne, 10);  // 10 is the default value

    // Get a value of type float
    setData("some_float_value", valTwo, 0.05f);  // 0.05 is the default value

}

One way to do this is to have a va_list. Is there a way I can accomplish this with a class?

Thanks

Was it helpful?

Solution

I guess you were almost there:

template<typename T>
void setData(char * environmentVariable, T &data, T defaultValue)
{
    // ...
}

This should do what you want. Notice, however, that the same T is used for the last two arguments, so this function call would make it impossible to deduce T:

setData("some_float_value", valTwo, 0.05); 

Because 0.05 is a double, while valTwo is a float. During type deduction, a similar conversion won't be performed, since the compiler is trying to match the exact types.

This is easy to fix though:

setData("some_float_value", valTwo, 0.05f); 
//                                      ^

The f suffix makes the last argument is a prvalue of type float, so that T can be deduced to be float.


Possibly, you may want to allow different types for the second and the third argument, as long as the third one can be converted to the second one. In this case, you could redefine your function template as follows:

template<typename T, typename U>
void setData(char * environmentVariable, T &data, U defaultValue)
{
    // ...
}

However, notice that this would give you the freedom to instantiate setData() with any two types T and U, while you probably want your template to be instantiated only for Us which are convertible to Ts. Some SFINAE trick combined with the std::is_convertible<> type trait will do the job:

#include <type_traits>

template<typename T, typename U,
         typename std::enable_if<
             std::is_convertible<U, T>::value
             >::type* = nullptr>
void setData(char * environmentVariable, T &data, U defaultValue)
{
    // ...
}

Now you can even use your original call without getting compiler errors:

setData("some_float_value", valTwo, 0.05); 
//                                  ^^^^
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top