2
\$\begingroup\$

I'm using the boost::units library (boost::units) and trying to make use of auto and decltype to deal with all the complicated types it produces.

I have a templated function to integrate a mathematical function (which might accept x values with units such as 1*metre) between two points:

template <class Out, class In >
auto integrate( std::function<Out(In)> const & f,
In xmin, In xmax, int nSteps)
-> decltype( f(xmin)  * xmin  )

Now I want to use this with some functions that have big ugly return types. I have written this:

//Standard quantities
quantity<temperature> stdBlackBodyTemp = 2857.0*kelvin;
auto luminousEfficiency = quantity<luminous_flux>(682.0*lumen) / quantity<power>(1.0 * watt);

//Integration range
quantity<length> minWavelength(150.0 * nano * metre);
quantity<length> maxWavelength(600.0 * nano * metre);

//Get type for spectral_differential_current
quantity<length> fakeLength(300.0 * nano * metre);

typedef decltype(pmt_radiant_sensitivity(fakeLength)
        * plancklaw(fakeLength, stdBlackBodyTemp)) sdctype;

//Define spectral_different_current function
std::function< sdctype(quantity<length>)>
    spectral_differential_current = [&stdBlackBodyTemp](quantity<length> l)
    {
        return
            pmt_radiant_sensitivity(l) * plancklaw(l, stdBlackBodyTemp );
    };

//Integrate over spectral_differential_current
auto differential_current = integrate( spectral_differential_current,
        minWavelength, maxWavelength, 100);

To define my std::function spectral_differential_current which I'm going to give to integrate I need to know the return type. The only way I have found to get this is by using the function on some random value (fakeLength) and then using decltype. It seems odd that I have to introduce a variable which isn't actually used just to get a type. Is there a better way of approaching this?

\$\endgroup\$
2
  • \$\begingroup\$ You could re-use minWavelength instead of introducing fakeLength. Since there could be multiple pmt_radiant_sensitivity and plancklaw with different return types, I'm not sure what you'd expect without giving the input type – and decltype has been constructed to take a standard expression, not some new syntax that only gets types and functions. \$\endgroup\$ Commented Mar 7, 2013 at 12:51
  • \$\begingroup\$ Thanks. I see your point that the return type can't be deduced without the arguments. Is there a better approach I could have taken? I've seen comments in other places suggesting that std::function is really only meant for very specific circumstances. Is this one of them or could my integrate function accept something else? \$\endgroup\$
    – paco_uk
    Commented Mar 7, 2013 at 20:11

1 Answer 1

1
\$\begingroup\$

I'm not sure why you need the typedef in the first place. Is there anything wrong with auto spectral_differential_current = ...?

On a similar note, why do you want to require that f is an std::function, disallowing reasonable calls like integrate(sin, 0, 2, 10)? Most code of this type can happily accept anything that can be called:

template <typename F, typename In>
auto integrate(F f, In xmin, In xmax, int nSteps)
-> decltype(f(xmin)  * xmin)

The compiler will tell you whether a given f is OK. Usually by not finding a suitable integrate function – SFINAE.

Also note the use of typename – that's just a stylistic thing of course, but e.g., double is not a class, so I prefer not to say class for template parameters that would accept a double or a plain function pointer.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks, that works! I didn't realise you could directly assign a lambda to a variable without wrapping it in a std::function. I've taken your typename advice as well. \$\endgroup\$
    – paco_uk
    Commented Mar 8, 2013 at 11:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.