Zhu Pan
Zhu Pan

Reputation: 1

Ambiguous call on overloaded variadic template function

I downloaded a C++ library to support multiple dimension array from github, when I built it using GCC8.2.0, the complier ran into a message saying an overrload function is ambiguous. Consider following code:

// basic function, set the length i for the dimension D
template<int Rank,int D>
void set_array(std::array<int,Rank>& A,int i)
{
    A[D] = i;
}

// function with parameter pack, set the length for all dimensions recursively
template<int Rank,int D,typename... indices>
void set_array(std::array<int,Rank>& A,int i,indices... idx)
{
    A[D] = i;
    set_array<Rank,D+1>(A,idx...);
}

// class calls set_array in allocation
template<typename T,int Rank>
class MultiArray
{

private:
    std::array<int,Rank> _dim = {{0}};

    template<typename... indices>
    void allocate(indices... idx) {
        static_assert(sizeof...(idx) == Rank,
                      "NUMBER OF INDICES PASSED TO ALLOCATE DOES NOT MATCH RANK OF ARRAY");
        set_array<Rank,0>(_dim,idx...);
    }
};

// code to create object of above MultiArray class.

MultiArray<int, 1> a;
a.allocate(10)

The compiler error message is: call of overrloaded "set_array<1,0>(std::array&, int&) is ambiguous,

My understanding is when calling set_array<1, 0>(_dim, 10), the compiler can not know which one should be used because the parameter pack can be empty. I tried some ways to fix but failed. Is there any solution to help me out? Thank you in advance!

Upvotes: 0

Views: 109

Answers (2)

NathanOliver
NathanOliver

Reputation: 180510

Your problem here is parameter packs are allowed to be empty. If you do have an empty pack, then

void set_array(std::array<int,Rank>& A,int i,indices... idx)

is just

void set_array(std::array<int,Rank>& A,int i)

which matches your non-variadic template. You need to handle having an empty parameter pack and easiest way to do that is to add an extra parameter like

template<int Rank,int D, typename First, typename... Rest>
void set_array(std::array<int,Rank>& A,int i,First first, Rest... rest)
{
    A[D] = i;
    set_array<Rank,D+1>(A,first, rest...);
}

and now if you call the function with only 2 parameters you'll get the non variadic overload and 3 or more will call the variadic one.

Upvotes: 1

Daniel
Daniel

Reputation: 31579

A straightforward way to solve this is to require at least one parameter for the second overload, by unrolling it once

template<int Rank,int D,typename index0, typename... indices>

Upvotes: 0

Related Questions