Search code examples
c++templates

Deducing templated struct in template functions parameters


Consider the following code:

template <typename RetType, typename ResultFlagType>
struct Ret
{
    RetType         value;
    ResultFlagType  flag;

    operator        RetType()           { return value; }
    operator        ResultFlagType()    { return flag; }
};

template <typename T>
struct StructType
{
    T       a;
    float   b;
    char    c;
};



enum class ResultFlag
{
    Success,
    Failure,
};

template <typename T>
Ret<StructType<T>, ResultFlag> BuildStruct(T a, float b, char c)
{
    return { { a, b, c }, ResultFlag::Success };
}

template <typename T>
Ret<StructType<T>, ResultFlag> ModifyStruct(StructType<T> s)
{
    s.b += 3;
    return { s, ResultFlag::Success };
}



int main()
{
    auto ret = BuildStruct(3, 2.1, 'a');
    if (ret == ResultFlag::Success)
    {
        ModifyStruct(ret);
    }
}

In the current form, the compiler (GCC in this case) will fail the deduction/substitution step complaining that "Ret<StructType<int>, ResultFlag>' is not derived from 'StructType<T>"

Let's say we're not allowed to change main(), ModifyStruct(), or struct StructType, is there a way to instruct the compiler to correctly deduce, or cast, ret to the proper type automatically for us?

The only way I found so fa is to explicitly cast to the correct type when passing ret to ModifyStruct:

if (ret == ResultFlag::Success)
{
    ModifyStruct((StructType<int>)ret); // Don't mind the C-Style cast.
}

Solution

  • Your problem is that template deduction happens before conversions are considered in overload resolution, so T can't be deduced. This is one of the reasons that implicit conversion operators are not a great idea.

    Not sure if this counts as "changing" ModifyStruct, but you can add an overload

    template <typename T>
    Ret<StructType<T>, ResultFlag> ModifyStruct(Ret<StructType<T>, ResultFlag> ret)
    {
        return ModifyStruct(ret.value);
    }