Search code examples
c++templates

C++ Could not match `Container<typename Container::value_type>`


The below serialize function doesn't match with the call. The serialize function should match a pair that contains a std::string and an iterable type that has a parameter.

#include <variant>
#include <string>
#include <vector>
#include <ranges>


namespace S
{
typedef int Error;

typedef std::string Json;

std::variant<Json, Error> serialize(std::pair<std::string, int> entry)
{
    return std::to_string(entry.second);
}

template <template <typename> typename Container>
std::variant<Json, Error> serialize(std::pair<std::string, Container<typename Container::value_type>> entry)
{
    return Json();
}
}


int main()
{
    std::vector<int> v = { 1, 2, 3 };
    S::serialize<std::vector<int>>(std::pair<std::string, std::vector<int>>{ "a", v });
    return 0;
}

The error is error C2672: 'S::serialize': no matching overloaded function found

Any idea why? What would an workaround look like?


Solution

  • This is common mistake to pack in template function parameters to many details about requirement.

    Make your template more general then use SFINAE to limit given template parameter.

    template <typename T, typename = typename T::value_type>
    std::variant<Json, Error> serialize(const std::pair<std::string, T>& entry)
    {
        (void)entry;
        return Json();
    }
    

    Live demo.

    Now your attempt:

    template <template <typename> typename Container>
    std::variant<Json, Error> serialize(std::pair<std::string, Container<typename Container::value_type>> entry)
    

    Note you are trying explain that Container template depends on itself Container<typename Container::value_type>>. This self reference is like Russell's paradox.
    Even assuming this is a good approach formally this should look like:

    template <template <typename> typename Container>
    std::variant<Json, Error> serialize(std::pair<std::string, Container<typename Container<typename Container< .... >::value_type>>::value_type>> entry)
    

    After all Container is template template parameter, so to use it as a type it needs template parameter.