Предыдущий вопрос: std :: наследование строковых классов и утомительное разрешение перегрузки c ++
В шагах после предыдущего вопроса я попытался проверить operator+
по необработанному указателю строки: "aaa" + path_string{ "bbb" }
. И обнаружил, что он не вызывает соответствующую функцию друга класса path_string
.
Я пытался добавить не шаблон перегрузки operator+
(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;
}
Вывод для 3-х компиляторов: gcc 5.4, clang 3.8.0, msvc 2015 (19.00.23506)
-333 / BBB-
https://rextester.com/BOFUS59590
Как я вспомнил, стандарт C ++ поясняет это так, как шаблонная функция должна выполняться только тогда, когда ни одна не шаблонная функция не соответствует точно аргументам. Но оператор (2)
должен точно совпадать, но почему тогда он даже не вызывается?
Если удалить (3)
, тогда (1)
будет вызывать вместо (2)
, что лучше (1)
.
Что здесь происходит?
PS : Я думаю, что это та же проблема с const
+ single reference
, как и в предыдущем вопросе.