lundi 28 octobre 2019

Function overload resolution with {}

So our C++ library lets users pass in lists of values wrapped in classes with variadic constructors so the lengths of these lists can be checked at compile time. I'm trying to add some new functionality by adding new overloaded functions. However, the 'wrong' overload is being called when I pass a zero-length array of parameters e.g. {}. The following minimal example illustrates the issue:

#include <iostream>
#include <vector>

class EmptyList
{
public:
    template<typename... T>
    EmptyList(T&&... vals)
    {
        static_assert(sizeof...(vals) == 0, "Wrong number of values");
    }

    std::vector<double> getValues() const { return {}; }
};

void testVector(int *a, std::vector<double> b)
{
    std::cout << "Vector: A (" << a << ")" << std::endl;
}

void testVector(std::vector<double> a, std::vector<double> b)
{
    std::cout << "Vector: B" << std::endl;
}

void testInitList(int *a, std::initializer_list<double> b)
{
    std::cout << "Init list: A (" << a << ")" << std::endl;
}

void testInitList(std::initializer_list<double> a, std::initializer_list<double> b)
{
    std::cout << "Init list: B" << std::endl;
}

void testEmptyList(int *a, const EmptyList &b)
{
    std::cout << "Empty list: A (" << a << ")" << std::endl;
}

void testEmptyList(const EmptyList &a, const EmptyList &b)
{
    std::cout << "Empty list: B" << std::endl;
}

int main()
{
    testVector({}, {});
    testInitList({}, {});
    testEmptyList({}, {});
}

The output is:

Vector: A (0)
Init list: B
Empty list: A (0)

Not only does the overloading behaviour seems weird, but there seems to be some sort of compiler special case for std::initializer_list making it behave differently to both my class and std::vector. Is there any way of working around this so the function overload taking my class is chosen over the one taking the pointer?

Aucun commentaire:

Enregistrer un commentaire