c++templates

Typedef that allows template template argument type deduction


Consider a situation where a code uses matricies at many points, so we have defined a typedef for a matrix type:

#include <cstddef>

template<typename Scalar, size_t size_x, size_t size_y>
class MatrixImpl {};

template<typename T>
using Matrix5x5 = MatrixImpl<T, 5, 5>;

I only add the MatrixImpl type here to have complete example, but it could also come from an external library or similar.

Now, consider this exemplary function like this:

template<typename Scalar, template<typename> typename MatrixType>
MatrixType<bool> toBool(const MatrixType<Scalar> &) { return MatrixType<bool>{}; }

int main() { Matrix5x5<bool> x = toBool<int, Matrix5x5>(Matrix5x5<int>{}); }

The problem is, that I always have to explicitly specify the template arguments for the function, because the compiler does not consider the using declaration as a thing to deduce the template arguments.

How can I change that declaration that allow type deduction?

What I want is that the following code would compile without an error:

#include <cstddef>

template<typename Scalar, size_t size_x, size_t size_y>
class MatrixImpl {};

template<typename T>
using Matrix5x5 = MatrixImpl<T, 5, 5>;

template<typename Scalar, template<typename> typename MatrixType>
MatrixType<bool> toBool(const MatrixType<Scalar> &) { return MatrixType<bool>{}; }

int main() { Matrix5x5<bool> x = toBool(Matrix5x5<int>{}); }

Here is the error I'm getting:

main.cpp: In function 'int main()':
main.cpp:11:20: error: no matching function for call to 'toBool(Matrix5x5<int>)'
   11 | int main() { toBool(Matrix5x5<int>{}); }
      |              ~~~~~~^~~~~~~~~~~~~~~~~~
main.cpp:11:20: note: there is 1 candidate
main.cpp:9:18: note: candidate 1: 'template<class Scalar, template<class> class MatrixType> MatrixType<bool> toBool(const MatrixType<Scalar>&)'
    9 | MatrixType<bool> toBool(const MatrixType<Scalar> &) {}
      |                  ^~~~~~
main.cpp:9:18: note: template argument deduction/substitution failed:
main.cpp:11:20: note:   'Matrix5x5<int>' {aka 'MatrixImpl<int, 5, 5>'} is not derived from 'const MatrixType<Scalar>'
   11 | int main() { toBool(Matrix5x5<int>{}); }
      |              ~~~~~~^~~~~~~~~~~~~~~~~~

EDIT:

My goal would be that I can call the function without specifying any template arguments, in the same way as it works if the arguments had default values. Similar to this:

This is only added to show that defaults arguments behave the way I want my using declaration to behave.

#include <cstddef>

template<typename Scalar, size_t size_x=5, size_t size_y=5>
class MatrixImpl {};

template<typename Scalar, template<typename> typename MatrixType>
MatrixType<bool> toBool(const MatrixType<Scalar> &) { return MatrixType<bool>{}; }

int main() { MatrixImpl<bool> x = toBool(MatrixImpl<int>{}); }

Solution

  • From your question, I don't know what MatrixType<bool> should result in, but here's how you solve the function argument deduction part:

    #include <cstddef>
    #include <type_traits>
    
    template <typename Scalar, size_t size_x, size_t size_y>
    class MatrixImpl {};
    
    template <class T>
    using Matrix5x5 = MatrixImpl<T, 5, 5>;
    
    template <template <class, auto...> class MatrixType, class Scalar, auto... Args>
    auto toBool(const MatrixType<Scalar, Args...>&) {
        return MatrixType<bool, Args...>{};
    }
    
    int main() {
        auto rv = toBool(Matrix5x5<int>{});
        static_assert(std::is_same_v<decltype(rv), MatrixImpl<bool, 5, 5>>);
    }