Reputation: 69
In special scenarios
I have this data structure
namespace x3 = boost::spirit::x3;
struct one;
struct two : x3::variant<x3::forward_ast<one>,int>{
using base_type::base_type;
using base_type::operator=;
two& operator=(const std::string& rhs){
return *this;
}
two& operator=(const std::string&& rhs){
return *this;
}
};
struct one : x3::variant<boost::recursive_wrapper<two>,std::string>{
using base_type::base_type;
using base_type::operator=;
};
In this case, the assignment is OK
one on{"sssss"};
two wo{22};
wo = 123;
on = std::string("vvvvvvvvvvv");
on = wo;
But when I directly assign a string to wo, it prompts an error:
wo = on;
// wo = one("sadfasdfas"); //You can't do this
wo = std::string("sadfasdfas"); <----【/usr/local/include/boost/variant/variant.hpp:2172:14: Candidate function not viable: no known conversion from 'std::string' to 'boost::variant<boost::spirit::x3::forward_ast<one>, int>' for 1st argument】
I have overloaded the relevant functions, but it seems to have no effect。 Who knows why this is and tell me how to make the correct modifications
Upvotes: 0
Views: 85
Reputation: 1055
The problem is that you overloaded two::operator=
for const std::string&
and const std::string&&
, neither of which is the best match for overload resolution with (non-const) rvalue argument std::string("vvvvvvvvvvv")
. Instead, the best match comes from x3::variant::operator=(T&&)
(source) which you included with using base_type::operator=
:
template <typename T, class = non_self_t<T>>
variant& operator=(T&& rhs) BOOST_NOEXCEPT_IF((std::is_nothrow_assignable<variant_type, T&&>::value))
{
var = std::forward<T>(rhs);
return *this;
}
The line var = std::forward<T>(rhs);
results in compilation error you mentioned (var
is boost::variant<boost::spirit::x3::forward_ast<one>, int>
to which a string cannot be assigned).
To make your overloads work as intended you can just make your rvalue assignment operator accept non-const rvalue reference to make it higher priority in overload resolution than templated operator=
(and to actually make it possible to adequately implement, because you wouldn't be able to move from const std::string&&
anyway):
two& operator=(std::string&& rhs) {
return *this;
}
(godbolt)
Note that you don't need to 'break inheritance cycle' second time in one
by boost::recursive_wrapper
, it can be removed. Also, // wo = one("sadfasdfas");
can be uncommented and work as intended as well.
Upvotes: 1