armundle
armundle

Reputation: 1179

Template function return type deduction in C++03

I would like to implement the following in C++03:

template <typename T1, typename T2>
T1 convert(bool condition, T2& value)
{
    return condition ? value : conversionFunction(value);
}

Except I would like to call convert without having to explicitly specify T1. How do I do that?

Upvotes: 2

Views: 367

Answers (2)

Oberon
Oberon

Reputation: 3249

Return types are not deduced by the compiler (this is consistent with overloading being not supported on return types). You have to specify this template parameter explicitly, e.g. by calling

convert<Obj>(x);

The second template parameter does not have to be specified, it can be deduced even though the first template parameter has been specified explicitly (so always put the template parameters that will need explicit specification before the ones that can be deduced!).

However, that only works if both the return type of conversionFunction and T2& are convertible to T1; since the compiler cannot know what value condition has at runtime, it has to ensure that both "branches" of the ?: are compileable. In that case, use typename boost::common_type<T1, ReturnTypeOfConversionFunction>::type as return value. If you cannot easily determine ReturnTypeOfConversionFunction, you could use Boost.TypeOf.

If the condition can be evaluated at compile time and depends only on T2, you can use template-metaprogramming instead:

template <bool condition, typename T2>
struct Converter;

template<typename T2>
struct Converter<true, T2> { // If the condition is true, use this.
    typedef T2 type;
    static type doConvert(T2& value) { return value; }
};

template<typename T2>
struct Converter<false, T2> { // If the condition is false, use this.
    typedef ReturnTypeOfConversionFunction type;
    static type doConvert(T2& value) { return conversionFunction(value); }
};

template <typename T2>
typename Converter</* condition */, ReturnTypeOfConversionFunction>::type
convert(T2& value)
{
    return Converter<condition, T2, ReturnTypeOfConversionFunction>::doConvert(value); 
}

In place of /* condition*/, the type traits from Boost might be helpful.

The syntax used for Converter is called a partial template specialization. See here for why typename is needed when specifying the return value of convert.

Upvotes: 0

jxh
jxh

Reputation: 70502

Perhaps you could use a hack. The hack is to defer the conversion until you actually use the return value. The return value is a helper object that allows itself to be converted to something else.

template <typename T>
struct ConvertHack {
    T &value_;
    const bool cond_;
    ConvertHack (bool cond, T &value) : value_(value), cond_(cond) {}
    template <typename U> operator U () const {
        return cond_ ? value_ : conversionFunction(value_);
    }
};

template <typename T>
ConvertHack<T> convert(bool condition, T& value) {
    return ConvertHack<T>(condition, value);
}

Upvotes: 2

Related Questions