M.Mac
M.Mac

Reputation: 739

How to take a class, that uses a parameter pack and typename, as an input parameter for a function(c++)

I created a class that takes a typename template variable and a parameter pack. In the next step i want to be able to pass two objects of that class to my function.

My main problem is, passing the template parameters and the objects correctly to be able to use my function. My class implementation.

//auto as template parameter is for non-type parameter(c++17)
template <auto value> constexpr auto DIM = value;
//constexpr on values in header files(c++17)
inline constexpr auto const DIM3 = DIM <3>;
inline constexpr auto const DIM2 = DIM <2>;


enum Index : int {lower = 0, upper = 1};


template<int base, int exponent>
int constexpr pow(){
    if constexpr(exponent == 0){
        return 1;
    }else{
        return base * pow<base, exponent-1>();
    }
}
template<int Size, typename T>
struct Array{
    T array[Size];
    Array(const T * a){
        for(int i = 0; i < Size; i++){
            array[i] = a[i];
        }
    }
};



//auto as template parameter is for non-type parameters(c++17)
template<typename T = double, auto ...IndicesN>
class MatrixND{

private:
    const Array<pow<DIM3, sizeof...(IndicesN)>(), T> matrix;

public:
    MatrixND(const T * arr): matrix(arr){}

    template<auto ...args>
    auto constexpr getElement(){
    }
};

The function that takes MatrixND objects:

template<auto posT1, auto posT2, typename A, typename B>
auto constexpr function(const MatrixND<A> tensor1, const MatrixND<B> tensor2){

    return 0;
}

I tried the following, but it throws an error message "no matching function call":

const double arrayc[27] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27};
auto matrix1 = new MatrixND<double, upper, lower, lower>(arrayc);

function<1,1, decltype(matrix1), decltype(matrix1)>(matrix1, matrix1);

The error message:

error: no matching function for call to ‘function<1, 1, MatrixND<double, (Index)1, (Index)0, (Index)0>*, MatrixND<double, (Index)1, (Index)0, (Index)0>*>(MatrixND<double, (Index)1, (Index)0, (Index)0>*&, MatrixND<double, (Index)1, (Index)0, (Index)0>*&)’
     contraction<1,1, decltype(matrix1), decltype(matrix1)>(matrix1, matrix1);

Upvotes: 1

Views: 63

Answers (2)

NathanOliver
NathanOliver

Reputation: 180415

You need to add the parameter packs to the template parameters of function. Using

template<auto posT1, auto posT2, typename A, typename B, auto ...AIndicesN, auto ...BIndicesN>
auto constexpr function(const MatrixND<A, AIndicesN...> tensor1, const MatrixND<B, BIndicesN...> tensor2){

    return 0;
}

Allows you to call function like

auto foo = function<1,1>(matrix1, matrix1);

Do note that for this to compile with your code you need to change

auto matrix1 = new MatrixND<double, upper, lower, lower>(arrayc);

to

auto matrix1 = MatrixND<double, upper, lower, lower>(arrayc);

since you don't actually want a pointer to a MatrixND but an actual MatrixND object.

Upvotes: 4

Some programmer dude
Some programmer dude

Reputation: 409136

When you call the function as

function<1,1, decltype(matrix1), decltype(matrix1)>(matrix1, matrix1);

you say that the template arguments A and B are decltype(matrix1), meaning they are really MatrixND<double, upper, lower, lower>.

That in turn means that e.g. the argument tensor1 will have the type const MatrixND<MatrixND<double, upper, lower, lower>>. Which is not what you pass.

A possible solution would be to not use MatrixND<A> (and MatrixND<B>) in the argument list, but only

template<auto posT1, auto posT2, typename A, typename B>
auto constexpr function(const A tensor1, const B tensor2){

    return 0;
}

And you should probably pass references instead of values as arguments as well.


If you do like above with the function you also don't need the template arguments for the types of A and B as that would be deduced by the compiler:

function<1,1>(matrix1, matrix1);

Upvotes: 2

Related Questions