如何让编译器选择非成员函数重载

Krz*_*iak 2 c++ overload-resolution c++17

我正在编写一个库,它对内置类型(int、float、double 等)和用户提供的类型执行一些操作。其中之一是由模板函数执行的:

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();
}
}
Run Code Online (Sandbox Code Playgroud)

这是一个定制点 - 用户可以根据自己的类型重载此函数:

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

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

或者将from_string函数放在同一命名空间中并通过 ADL 访问:

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

现在,除了字符串到类型的转换之外,该库还执行类型到字符串、比较以及其他一些操作。我想通过一系列类来完成它,这些类将值保存为以下实例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;
        }
}
}
Run Code Online (Sandbox Code Playgroud)

为了方便起见,我想使用这些TypeHandlerT课程。

但是,使用这样的代码,当我尝试使用时,会出现以下编译器错误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 ]
Run Code Online (Sandbox Code Playgroud)

看来会员版from_string隐藏了免费功能版。

有没有办法优雅地解决这个问题?例如,通过将 free 函数引入作用域(但如何在不排除 ADL 的情况下做到这一点?)?

我知道一个简单的解决方法是重命名成员或自由函数,但我想避免这种情况。

HTN*_*TNW 5

基于范围的查找从 的主体开始,TestHandlerT<T>::from_string在命中之前命中成员函数lib::from_string。所以只需将 重新引入lib::from_string到 body 的范围即可using。这也会重新启用 ADL,因为当基于范围的查找命中类成员时,ADL 会被抑制。

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 普通的非限定查找通常只查找来自单个范围的声明。如果这是一个成员函数或一组重载成员函数,则 ADL 不适用。但是,通过内部作用域中的“using”声明,可以找到该声明而不是成员函数,然后 ADL 可以应用并查找其他声明。 (2认同)