Search code examples
c++templatessfinaetemplate-templates

template template argument deduction with sfinae


The template template argument can't be deduced for both foo and foo2.

If I remove the sfinae part, the template template argument was successfully deduced for both foo and foo2.

How to fix either the span class or foo and foo2?

Thanks.

Test (also at godbolt.org)

#include <type_traits>

template<typename T>
using enable_if_t_const = typename std::enable_if<
        std::is_const<T>::value
>::type;

template<typename T, typename=void> class span;

template<typename T>
class span<T, enable_if_t_const<T>> {
public:
    explicit span(const T* const data) {}
};

template <typename T, template<typename> class S> 
void foo() {}

template <typename T, template<typename> class S> 
void foo2(S<T>& s) {}

int main() {
    int arr[] = {1};
    span<const int> s(arr);
    foo<const int, span>();
    foo2(s);
    return 0;
}

Solution

  • This is because, although you have a default template parameter, span isn't a template <typename> class S. It's a template <typename, typename> class S.

    The easiest fix is to change it to

    template <typename T, template<typename...> class S> 
    void foo2(S<T>& s) {}
    

    So that you can accept any S that takes any number of types (although we only use it with one).

    Demo