Search code examples
c++functiontemplatestypename

Change typename type into the template function (c++)


So I'm currently working on upgrading my skills with templates and I'm stuck with something.

I want to, if one of my objects uses floating_point numbers and I do math operation with another object which is of type integral, to return an object of type floating point. But I can only know when they're already in the function and I would like to know if there is a way to force our typename to be some defined type.

EDIT: I saw that my post lacked of example so I will show you the function I'm working on.

// Addition : +
template <typename TYP_O1, typename TYP_O2, typename TYP_RE> 
requires (std::integral<TYP_O1> || std::floating_point<TYP_O1>) &&(std::integral<TYP_O2> || std::floating_point<TYP_O2>)

MultiArray<TYP_RE> operator+(MultiArray<TYP_O1>& rMultiArr1, MultiArray<TYP_O2>& rMultiArr2){
    // Création d'un array qui sera la somme des deux MultiArray un à un
    std::vector<TYP_RE> Array;

    for(int i = 0 ; i < (int)rMultiArr1.getArray().size() ; i++) {
        // On les récupère par référence pour faciliter la lecture.
        std::vector<TYP_O1>& Arr1 = rMultiArr1.getArray();
        std::vector<TYP_O2>& Arr2 = rMultiArr2.getArray();

        // On rajoute la somme à la fin du Array
        Array.push_back((TYP_RE)Arr1[i] + Arr2[i]);
     }

    // On crée le MultiArray de la somme des 2
    MultiArray<TYP_RE> result_MultiArr = {rMultiArr1.getDim(), rMultiArr1.getShape(), Array};

    // On renvoie ce MultiArray nouvellement crée
    return result_MultiArr;
}

(I've just erased the errors check)

So in the template: TYP_O1 is the type of the first object and TYP_O2 is the type of the second object.

TYP_RE is the return type and THIS is the typename that I want to force to be a double if one of the MultiArray is of type "floating_point" (and the other one is "integral")


Solution

  • In general, you can use std::conditional to choose a type based on a condition.

    A basic example:

    template<typename LHS, typename RHS>
    auto plus(LHS lhs, RHS rhs) -> std::conditional_t<
        std::is_same_v<LHS, double> || std::is_same_v<LHS, double>,
        double,
        int
    > {
        return lhs + rhs;
    }
    

    The return type of plus will be double if either of the arguments is a double, otherwise it will be int. Note that it doesn't make much sense here because lhs + rhs is already a double if either lhs or rhs is (assuming they are basic arithmetic types, not including long double or pointer types).

    In your case (since you've added a code snippet), your could do something like this:

    template<typename TYP_O1, typename TYP_O2>
    using MultiArraySumResult = std::conditional_t<
        std::is_floating_point_v<TYP_01>,
        MultiArray<TYP_01>,
        MultiArray<TYP_02>
    >
    // or...
    template<typename TYP_O1, typename TYP_O2>
    using MultiArraySumResult = MultiArray<std::conditional_t<
        std::is_floating_point_v<TYP_01> || std::is_floating_point_v<TYP_02>,
        double,
        int
    >>
    

    Then you just use MultiArraySumResult<TYP_O1, TYP_O2> as your return type. You can even no specify the return type (auto without trailing return type), put that using declaration inside the function, and use it for the local variable that you return:

    template <typename TYP_O1, typename TYP_O2, typename TYP_RE> 
    requires (std::integral<TYP_O1> || std::floating_point<TYP_O1>) &&(std::integral<TYP_O2> || std::floating_point<TYP_O2>)
    auto operator+(MultiArray<TYP_O1>& rMultiArr1, MultiArray<TYP_O2>& rMultiArr2){
        using ReturnType = std::conditional_t<
            is_floating_point_v<TYP_01>,
            MultiArray<TYP_01>,
            MultiArray<TYP_02>
        >
        ReturnType Array;
        // [...]
        return ReturnType{rMultiArr1.getDim(), rMultiArr1.getShape(), Array};
    }