O_o
As I said, there are a lot of ways you can do it.
Soma
Code:
template
<
typename F1
, typename F2
, bool FUse1
, bool FUse2
>
struct MGetOperatorConversionHelper
{
// raise a compiler error
};
template
<
typename F1
, typename F2
>
struct MGetOperatorConversionHelper<F1, F2, true, false>
{
typedef F1 UResult;
};
template
<
typename F1
, typename F2
>
struct MGetOperatorConversionHelper<F1, F2, false, true>
{
typedef F2 UResult;
};
template
<
typename F1
, typename F2
>
struct MGetOperatorConversionHelper<F1, F2, true, true>
{
// raise a compiler error
};
template
<
typename F1
, typename F2
>
struct MGetOperatorConversion
{
struct F1Result{unsigned int mUnused[16];};
struct F2Result{unsigned int mUnused[64];};
static F1Result GetOperatorConversion(F1);
static F2Result GetOperatorConversion(F2);
typedef typename MGetOperatorConversionHelper<F1, F2, (sizeof(F1Result) == sizeof(GetOperatorConversion(F1() + F2()))), (sizeof(F2Result) == sizeof(GetOperatorConversion(F1() + F2())))>::UResult UResult;
};
template
<
typename FTarget
>
struct MGetOperatorConversion<FTarget, FTarget>
{
typedef FTarget UResult;
};
template
<
typename F1
, typename F2
>
decltype(F1() + F2()) DoSomething1 // Both `F1' and `F2' must have default constructors.
(
F1 f1
, F2 f2
)
{
return(f1 + f2);
}
template
<
typename F1
, typename F2
>
auto DoSomething2
(
F1 f1
, F2 f2
) -> decltype(f1 + f2) // Places fewer requirements on `F1' and `F2' while working on fewer compilers.
{
return(f1 + f2);
}
template
<
typename F1
, typename F2
>
typename MGetOperatorConversion<F1, F2>::UResult DoSomething3 // Either `F1' or `F2' must be convertable to `F1' or `F2' as appropriate.
(
F1 f1
, F2 f2
)
{
return(f1 + f2);
}
#include <iostream>
#include <typeinfo>
int main()
{
std::cout << typeid(int).name() << ':' << typeid(DoSomething1(0, 5)).name() << '\n';
std::cout << typeid(float).name() << ':' << typeid(DoSomething1(0, 5.0f)).name() << '\n';
std::cout << typeid(double).name() << ':' << typeid(DoSomething1(0, 5.0)).name() << '\n';
std::cout << typeid(int).name() << ':' << typeid(DoSomething2(0, 5)).name() << '\n';
std::cout << typeid(float).name() << ':' << typeid(DoSomething2(0, 5.0f)).name() << '\n';
std::cout << typeid(double).name() << ':' << typeid(DoSomething2(0, 5.0)).name() << '\n';
std::cout << typeid(int).name() << ':' << typeid(DoSomething3(0, 5)).name() << '\n';
std::cout << typeid(float).name() << ':' << typeid(DoSomething3(0, 5.0f)).name() << '\n';
std::cout << typeid(double).name() << ':' << typeid(DoSomething3(0, 5.0)).name() << '\n';
return(0);
}