Search code examples
c++c++11templatesauto

C++11 auto return type in template methods


I would like to write a general function to search in different containers. Cointainers contain shared pointers to different types. At the moment I have this

    template<typename TInstance, typename THandle, typename TContainer>
    auto FindInContainer(TContainer& container, THandle handle) -> decltype(boost::shared_ptr<TInstance>())
    {
        std::lock_guard<std::mutex> lock(_mutex);

        const auto& found = std::find_if(container.begin(), container.end(), 
            [handle](typename TContainer::value_type& instance)
            {
                return instance.get() == reinterpret_cast<typename TContainer::value_type::element_type*>(handle.handle);
            });

        if (found == container.end())
            return boost::shared_ptr<TInstance>();

        return *found;
    }

I use MSVC 2015 Update 1, but somehow it cannot figure out the TInstance type, even though I used the return type specified (whatever the term for the thing for the -> operator in the method signature).

return FindInContainer<SensorController>(_sensors, handle); // Works
return FindInContainer(_sensors, handle); // Does not compile

The _sensors is defined as

std::vector<boost::shared_ptr<SensorController>> _sensors;

Is my C++ is rusty, or the compiler does not support this type deduction?


Solution

  • A template argument cannot be deduced from the return type of a function template. Only parameters of the function template participate in template argument deduction. Since TInstance does not figure in any of the parameters of FindInContainer, it cannot be deduced.

    If VS 2015 Update 1 supports it, you could use return type deduction (a C++14 feature) for the function template (omit the return type altogether):

    template<typename THandle, typename TContainer>
    auto FindInContainer(TContainer& container, THandle handle)
    {
      // ... as before
    }
    

    If that's not supported, you can resort to extracting the type from the container (as you're already doing):

    template<typename THandle, typename TContainer>
    typename TContainer::value_type FindInContainer(/*...*/)
    {
      // ... as before
    }