Reputation: 1179
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
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
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