Search code examples
c++templatesboosttemplate-meta-programmingtemplate-argument-deduction

Template argument deduction/substitution failed with Boost Hana type_c


I do not understand why the following simple example fails:

#include <boost/hana.hpp>

template <typename _T>
static constexpr void Foo(boost::hana::type<_T>) {
}

int main() {
    Foo(boost::hana::type_c<int>);
    return 0;
}

I get the following error message:

[build] error: no matching function for call to ‘Foo(boost::hana::type<int>&)’
[build]    74 |     Foo(hana::type_c<int>);
[build]       |     ~~~^~~~~~~~~~~~~~~~~~~
[build] note: candidate: ‘template<class _T> constexpr void Morphy::Foo(boost::hana::type<T>)’
[build]    61 | static constexpr void Foo(hana::type<_T>) {
[build]       |                       ^~~
[build] note:   template argument deduction/substitution failed:
[build] note:   couldn’t deduce template parameter ‘_T’
[build]    74 |     Foo(hana::type_c<int>);
[build]       |     ~~~^~~~~~~~~~~~~~~~~~~

The only way to make the above work is by making explicit the template argument of Foo by writing Foo<int>(boost::hana::type_c<int>). Why is the compiler unable to automatically deduce the template argument?

Notice that the above code works if I use boost::hana::basic_type in place of boost::hana::type in the declaration of Foo. Is this alternative approach correct?


Solution

  • type_c<int> is a variable template that creates a value of type type<int>. It indeed seems like Foo should easily deduce parameter _T from type<_T> when passing type<int>. However it is not possible because type is an alias template that refers to member of some auxiliary class and its parameter is always in non-deduced context.

    template< typename x_Type >
    struct FooImpl
    {
        using Type = x_Type;
    };
    
    template< typename x_Type >
    using Foo = typename FooImpl<x_Type>::Type;
    
    template< typename x_Type > // x_Type can not be deduced
    void Bar(Foo<x_Type>) {}
    
    int main()
    {
        Bar(Foo<int>{});
        return 0;
    }
    

    online compiler

    basic_type works because it is an actual type of type_c.