0

I'm fighting with the compiler and its ability to use automatic template deduction. The following does not compile, with a template automatic deduction failure:

template<typename Configuration, typename ConfigAlloc = std::allocator<Configuration>>
std::vector<Configuration, ConfigAlloc> ResamplePath(
        const std::vector<Configuration, ConfigAlloc>& path,
        const double resampled_state_distance,
        const std::function<double(const Configuration&, const Configuration&)>& state_distance_fn,
        const std::function<Configuration(const Configuration&, const Configuration&, const double)>& state_interpolation_fn)
{
    ...
}

void foo()
{
    std::vector<Eigen::Vector3d, Eigen::aligned_allocator<Eigen::Vector3d>> path;
    ...

    const auto interpolation_fn = [&] (
            const Eigen::Vector3d& prev,
            const Eigen::Vector3d& curr,
            const double ratio)
    {
        Eigen::Vector3d interpolated;
        ...
        return interpolated;
    };

    auto resample_result = ResamplePath(path, ..., interpolation_fn);
}

If I change either the lambda declaration to

    const std::function<Eigen::Vector3d(const Eigen::Vector3d&, const Eigen::Vector3d&, const double)> interpolation_fn = [&] (
            const Eigen::Vector3d& prev,
            const Eigen::Vector3d& curr,
            const double ratio)
    {
        Eigen::Vector3d interpolated;
        ...
        return interpolated;
    };

or I change the function call to explicitly define the types

auto resample_result = ResamplePath<Eigen::Vector3d, Eigen::aligned_allocator<Eigen::Vector3d>>(
                path, ..., interpolation_fn);

then everything compiles without any issues.

Is there something I'm missing that might allow autodeduction to work without explicitly defining the lambda type?

Edit: exact compile error

virtual_rubber_band.cpp: In member function ‘void smmap::VirtualRubberBand::resampleBand(bool)’:
virtual_rubber_band.cpp:279:111: error: no matching function for call to ‘ResamplePath(EigenHelpers::VectorVector3d&, const double&, const smmap::VirtualRubberBand::resampleBand(bool)::<lambda(const Vector3d&, const Vector3d&)>&, const smmap::VirtualRubberBand::resampleBand(bool)::<lambda(const Vector3d&, const Vector3d&, double)>&)’
                 band_, max_distance_between_rubber_band_points_, state_distance_fn, state_interpolation_fn);
In file included from virtual_rubber_band.cpp:3:0:
shortcut_smoothing.hpp:191:52: note: candidate: template<class Configuration, class ConfigAlloc> std::vector<_Tp, _Alloc> shortcut_smoothing::ResamplePath(const std::vector<_Tp, _Alloc>&, double, const std::function<double(const Datatype&, const Datatype&)>&, const std::function<Configuration(const Configuration&, const Configuration&, double)>&)
 inline std::vector<Configuration, ConfigAlloc> ResamplePath(
                                                ^
shortcut_smoothing.hpp:191:52: note:   template argument deduction/substitution failed:
virtual_rubber_band.cpp:279:111: note:   ‘const smmap::VirtualRubberBand::resampleBand(bool)::<lambda(const Vector3d&, const Vector3d&)>’ is not derived from ‘const std::function<double(const Datatype&, const Datatype&)>’
                 band_, max_distance_between_rubber_band_points_, state_distance_fn, state_interpolation_fn);
bitznarf
  • 3
  • 2
  • »The following does not compile, with a template automatic deduction failure« Is this a game where we have to guess what error you get? – Henri Menke Aug 21 '17 at 22:32
  • Questions seeking debugging help ("**why isn't this code working?**") must include the desired behavior, a *specific problem or error* and *the shortest code necessary* to reproduce it **in the question itself**. Questions without **a clear problem statement** are not useful to other readers. See: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – Henri Menke Aug 21 '17 at 22:32
  • I attempted to create a Minimal, Complete, Verifiable example, but such an example is very difficult to create as these are in different libraries; the minimal example that I was able to create was roughly 2000 lines of code. I'm adding the exact compile error as requested. – bitznarf Aug 21 '17 at 22:49

1 Answers1

1

A lambda is not a std function.

A std function is a type eraser. It erases ecerything except "invoke with signature", copy, and destroy (plus unimportant stuff).

Type deduction and type erasure are opposite operations. Deducing a type erasure type is code smell.

template<typename Configuration, typename ConfigAlloc = std::allocator<Configuration>,
  class Distance, class Interpolate>
std::vector<Configuration, ConfigAlloc> ResamplePath(
    const std::vector<Configuration, ConfigAlloc>& path,
    const double resampled_state_distance,
    const Distance& state_distance_fn,
    const Interpolate& state_interpolation_fn)

now we got rid of trying to deduce how to type erase, and ... stop type erasing. This can lead to runtime performance increases, as compilers find inlining over type erasure tricky.

template<typename Configuration, typename ConfigAlloc = std::allocator<Configuration>>
std::vector<Configuration, ConfigAlloc> ResamplePath(
    const std::vector<Configuration, ConfigAlloc>& path,
    const double resampled_state_distance,
    block_deduction<const std::function<double(const Configuration&, const Configuration&)>&> state_distance_fn,
    block_deduction<const std::function<Configuration(const Configuration&, const Configuration&, const double)>&> state_interpolation_fn)

where block_deduction prevents compilers from trying to deduce using those arguments.

template<class T>struct tag_t{using type=T;};
template<class T>using block_deduction=typename tag_t<T>::type;

Your real problem is probably that you want to use std::function as a concept -- you want the argument to be compatible with that signature -- which isn't part of C++ yet. Concepts may arrive in .

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • So assuming that I can't change the function prototype, it sounds like my best option may be to explicitly declare the template parameters as I have done? I may be able to get the function prototype changed, but that'll take a longer process at this point. – bitznarf Aug 21 '17 at 22:56
  • [This post](https://stackoverflow.com/questions/16111285/how-to-pass-and-execute-anonymous-function-as-parameter-in-c11) may help people get more details on Yakk's first resolution: – bitznarf Aug 21 '17 at 23:24
  • @bitz if you have broken code you cannot fix, write a wrapper; either option can be used to wrap the original. – Yakk - Adam Nevraumont Aug 21 '17 at 23:50
  • How compiler agnostic is the block_deduction technique? In particular I'm concerned about clang vs. g++ vs MSVC. This type of template metaprogramming is not something I'm familiar with. – bitznarf Aug 22 '17 at 00:09