代码之家  ›  专栏  ›  技术社区  ›  Andry

std::字符串类继承和繁琐的c++重载解析#2

  •  0
  • Andry  · 技术社区  · 7 年前

    上一个问题: std::string class inheritance and tedious c++ overload resolution

    operator+ "aaa" + path_string{ "bbb" } . 发现它不叫相应的 path_string 类友元函数。

    操作员+ (2) (3) 确实有用。

    #include <string>
    
    template <class t_elem, class t_traits, class t_alloc>
    class path_basic_string : public std::basic_string<t_elem, t_traits, t_alloc>
    {
    public:
        using base_type = std::basic_string<t_elem, t_traits, t_alloc>;
    
        path_basic_string() = default;
        path_basic_string(const path_basic_string & ) = default;
        path_basic_string(path_basic_string &&) = default;
    
        path_basic_string & operator =(path_basic_string path_str)
        {
            this->base_type::operator=(std::move(path_str));
            return *this;
        }
    
        path_basic_string(base_type r) :
            base_type(std::move(r))
        {
        }
    
        path_basic_string(const t_elem * p) :
            base_type(p)
        {
        }
    
        base_type & str()
        {
            return *this;
        }
    
        const base_type & str() const
        {
            return *this;
        }
    
        using base_type::base_type;
        using base_type::operator=;
    
        // ... all over operators are removed as not related to the issue ...
    
        // (1)
        friend path_basic_string operator+ (const t_elem * p, const base_type & r)
        {
            path_basic_string l_path = p;
            l_path += "xxx";
            return std::move(l_path);
        }
    
        friend path_basic_string operator+ (const t_elem * p, base_type && r)
        {
            if (!r.empty()) {
                return "111" + ("/" + r); // call base operator instead in case if it is specialized for this
            }
    
            return "111";
        }
    
        // (2)
        friend path_basic_string operator+ (const t_elem * p, path_basic_string && r)
        {
            base_type && r_path = std::move(std::forward<base_type>(r));
            if (!r_path.empty()) {
                return "222" + ("/" + r_path); // call base operator instead in case if it is specialized for this
            }
    
            return "222";
        }
    
        // (3) required here to intercept the second argument
        template <typename T>
        friend path_basic_string operator+ (const t_elem * p, T && r)
        {
            base_type && r_path = std::move(std::forward<base_type>(r));
            if (!r_path.empty()) {
                return "333" + ("/" + r_path); // call base operator instead in case if it is specialized for this
            }
    
            return "333";
        }
    };
    
    using path_string = path_basic_string<char, std::char_traits<char>, std::allocator<char> >;
    
    std::string test_path_string_operator_plus_right_xref(path_string && right_path_str)
    {
        return "aaa" + right_path_str;
    }
    
    int main()
    {
        const path_string test =
            test_path_string_operator_plus_right_xref(std::move(path_string{ "bbb" }));
        printf("-%s-\n", test.str().c_str());
    
        return 0;
    }
    

    -333/桶-

    https://rextester.com/BOFUS59590

    正如我记得的,C++标准澄清了这一点,就像模板化函数只有当没有模板函数没有被匹配的参数时才需要查找。但是 (2) 运算符必须精确匹配,但为什么不调用它呢?

    如果删除 (3) 然后 (1) (2) 哪个比哪个好 (1) .

    附言 const + single reference

    1 回复  |  直到 7 年前
        1
  •  2
  •   SergeyA    7 年前

    在以下代码段中:

    std::string test_path_string_operator_plus_right_xref(path_string && right_path_str)
    {
        return "aaa" + right_path_str;
    }
    

    right_path_str

    当模板重载不可用时,它将绑定到

    friend path_basic_string operator+ (const t_elem * p, const base_type & r)
    

    当模板存在时,它更适合于非常量左值引用:

    template <typename T>
    friend path_basic_string operator+ (const t_elem * p, T && r)
    

    在这种情况下, T&& 是一个转发引用,它折叠为非常量左值引用。要修复代码,请确保 move std::move std::forward

    std::string test_path_string_operator_plus_right_xref(path_string && right_path_str)
    {
        return "aaa" + std::move(right_path_str);
    }
    
    推荐文章