Как C++ выводит тип для шаблонов функций?

На самом деле я не подразумеваю на свой вопрос полного и исчерпывающего ответа, иначе меня можно просто отправить на cppreference читать это огромное чтиво. Когда-нибудь может и займусь этим, но в данный момент мой уровень английского не сильно позволяет это сделать. Но я хочу примерно представлять каким образом он решает выводить типы, а конкретно разберу мою проблему на примере:

#include <iostream>

template <typename T> 
T** createarray(int n, int m) {
    T** mas = new T*[n];
    for (int i = 0; i < n; i++) {
        mas[i] = new T[m];
    }
    return mas;
}

int main()
{
    int n, m;
    std::cin >>n >> m;
    double **arr = createarray(n, m);
}

Хочу создать двумерный массив, при этом чтобы элементы массива могли быть произвольного типа. Но код, не комплируется и оно в целом понятно, почему. Я пытаюсь вызывать функцию, в которой как бы не понятно, что такое тип T. Если бы например функция была такого вида:

T** createarray(int n, int m, T another_argument) {
    T** mas = new T*[n];
    for (int i = 0; i < n; i++) {
        mas[i] = new T[m];
    }
    return mas;
} 

То в целом становится более понятно, что надо сначала разобраться, что за тип нам передали и этого же типа будет функция. Но все же в контексте double **arr = createarray(n, m) ВРОДЕ КАК понятно, что функция тоже должна быть double? Однако тут встает другая проблема, я же могу вывести тип функции допустим как int, а потом кастануть к double? получается неоднозначность, что я могу привести к любому типу и потом просто кастануть неявно. Однако, что если я передам какую-то более сложную структуру данных по типу string? vector? Такой неоднозначности в целом уже не будет. Однако ошибки комплияции данная идея не устранила. Хотя в целом данные мысли не очень имеют место ввиду того, что я не совсем уверен как C++ действительно пытается выводить типы. Он по факту их выводит с помощью аргументов? Есть ли какой-то способ заставить мою функцию работать без явного указания типа: double **arr = createarray<double>(n, m).


Ответы (1 шт):

Автор решения: HolyBlackCat

Как вы уже заметили, на вывод аргументов не влияет то, как используется возвращаемое значение функции.

С единственным исключением - зашаблоненным operatorом преобразования:

template <typename T>
struct Helper
{
    int m, n;
    
    template <typename T>
    operator T **()
    {
        // Тут код создания массива.
    }
};

Helper CreateArray(int m, int n)
{
    return {m, n};
}

Тогда double **arr = createarray(m, n); заработает.

→ Ссылка