Home > front end >  How to make compiler choose a non-member function overload
How to make compiler choose a non-member function overload

Time:12-22

I am writing a library that performs some operations on built-in types (int, float, double, etc.) and user-provided types. One of those is performed by a template function:

namespace lib
{
template<typename T>
inline auto from_string(std::string const & s, T & t) -> bool
{
    std::istringstream iss(s);
    iss >> t;
    return !iss.fail();
}
}

This is a customisation point - users may overload this functions for their type:

namespace foo
{
class UserType
{
    // (...)
};
}

namespace lib
{
inline auto from_string(std::string const & s, foo::UserType & ut) -> bool
{
    // some implementation
}
}

or have the from_string function in the same namespace and accessible via ADL:

namespace foo
{
inline auto from_string(std:string const & s, UserType & ut) -> bool
{
    // some implementation
}
}
}

Now, apart from string-to-type conversion, the library also performs type-to-string, comparison, and some more operations. I would like to have it done via a family of classes that hold the value as an instance of std::any:

namespace lib
{
class TypeHandler
{
    public:
        virtual TypeHandler() = default;
        virtual auto from_string(std::string const & string, std::any & value) const -> bool = 0;
        // more functions
};

template<typename T>
class TypeHandlerT : public TypeHandler
{
    public:
        auto from_string(std::string const & string, std::any & value) const -> bool override
        {
            T val;
            if (from_string(string, val))  // an attempt to call the free function
            {
                value = val;
                return true;
            }
            return false;
        }
}
}

I want to use the TypeHandlerT classes for convenience.

However, with the code like this I get the following compiler error when I try to use TypeHandlerT<int>:

error C2664: 'bool lib::TypeHandlerT<T>::from_string(const std::string &,std::any &) const':
cannot convert argument 2 from 'T' to 'std::any &' with [ T=int ]

It seems the member version of from_string hides the free function version.

Is there a way to fix this elegantly? For example by bringing the free function into scope (but how to do that without excluding ADL?)?

I know an easy fix is to rename either the member or free function, but I would like to avoid this.

CodePudding user response:

Scope based lookup starting from the body of TestHandlerT<T>::from_string hits the member function before it hits lib::from_string. So just reintroduce lib::from_string into the scope of the body with using. This also reenables ADL, as ADL is suppressed when scope based lookup hits a class member.

template<typename T>
struct TypeHandlerT : TypeHandler {
    bool from_string(std::string const &string, std::any &value) const -> override {
        using lib::from_string;
        T val;
        if (from_string(string, val)) {
            value = val;
            return true;
        }
        return false;
    }
};
  • Related