This is my struct which uses implicit casting on creating variable.
#include <string>
#include <variant>
using namespace std;
using val = variant<int, string, double, bool, long, long long, long double>;
struct value
{
val innerVal;
value():innerVal(""){}
value(const val &c) : innerVal(c) {}
template <typename T>
operator T()
{
return get<T>(innerVal);
}
template <typename V>
value &operator=(const V &t)
{
innerVal = t;
return *this;
}
};
This is how I am using it when I construct a variable it works fine but when I assigned an already created variable to value
struct it gives error.
int main(int argc, char* argv[])
{
value h;
h = "String";
string m = h;// Here works fine
string b = "different";
b = h;//Here it gives error
}
Compiler error
use of overloaded operator '=' is
ambiguous (with operand types
'std::__ndk1::string' (aka
'basic_string<char, char_traits<char>,
allocator<char> >') and 'value')
b = h;
I want to implicitly construct the variable without encountering this error can someone explain how to resolve this issue.
The assignment b = h
is ambiguous, because std::string
has different operator=
. Because you have a templated conversion operator your compile does not know which overloaded operator=
of std::string
to take.
You can constrain the types of conversions allowed from value
to allow only implicit conversions to one of the member variant
s type. The following struct will provide a boolean telling us, whether type T
is contained in Type
's template parameters, using a fold expression:
template<typename, typename>
struct has_template_param;
template<typename T, template<typename ...> typename Type, typename ...Ts>
struct has_template_param<T, Type<Ts...>> {
static constexpr bool value = (... || std::is_same_v<T, Ts>);
};
Then the templated conversion operator can be constrained with SFINAE:
template<typename T, typename = std::enable_if_t<has_template_param<T, val>::value>>
operator T() {
return std::get<T>(innerVal);
}
Using C++20 concepts, it can be done more conveniently via
template<typename T, typename Type>
concept has_param = has_template_param<T, Type>::value;
and
template<has_param<val> T>
operator T() {
return std::get<T>(innerVal);
}