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;
}
};