I created two types : bool_t
and number_t
and I wanted to convert one into another (in the two ways). However, I got some issues to convert the bool_t
into a number_t
.
Basically what I want to do is that (but it does not compile) :
template<bool v>
struct bool_t {
template<template<int> typename T>
operator T<v ? 1 : 0>() {
return {};
}
};
template<int N>
struct number_t {
template<int n1, int n2>
friend number_t<n1 + n2> operator+(number_t<n1>, number_t<n2>) {
return {};
}
};
int main() {
number_t<0>{} + bool_t<0>{};
}
and the error is :
prog.cc:19:19: error: invalid operands to binary expression ('number_t<0>' and 'bool_t<0>')
number_t<0>{} + bool_t<0>{};
~~~~~~~~~~~~~ ^ ~~~~~~~~~~~
prog.cc:12:26: note: candidate template ignored: could not match 'number_t' against 'bool_t'
friend number_t<n1 + n2> operator+(number_t<n1>, number_t<n2>) {
^
1 error generated.
How to solve this problem?
User-defined conversions are never considered when attempting to match up function argument types with function parameter types for template argument deduction. So this issue is a somewhat more complicated version of this sort of error:
template <int> struct X {};
struct Y {
operator X<2> () const { return {}; }
};
template <int N>
void f(X<N>) {}
int main()
{
Y y;
f(y); // Error: Cannot deduce template argument.
}
Since it seems you're making something along the lines of a template meta-programming library, perhaps you could define a custom mechanism for converting types in your library "to a template"?
#include <type_traits>
template<bool v>
struct bool_t {
// (Add some appropriate SFINAE.)
template<template<int> typename T>
constexpr T<v ? 1 : 0> convert_template() const {
return {};
}
};
template<typename T, template<int> class TT>
struct type_specializes : std::false_type {};
template<template<int> class TT, int N>
struct type_specializes<TT<N>, TT> : std::true_type {};
template<int N>
struct number_t {
// Allow "conversion" to my own template:
template<template<int> typename T>
constexpr std::enable_if_t<type_specializes<number_t, T>::value, number_t>
convert_template() const { return {}; }
private:
// Used only in decltype; no definition needed.
template<int n1, int n2>
static number_t<n1 + n2> sum_impl(number_t<n1>, number_t<n2>);
template<typename T1, typename T2>
friend auto operator+(T1&& x, T2&& y)
-> decltype(number_t::sum_impl(
x.template convert_template<number_t>(),
y.template convert_template<number_t>()))
{ return {}; }
};
int main() {
number_t<0>{} + bool_t<0>{};
}
If you want to allow both operands to be bool_t
specializations, the operator+
will need to be a proper visible namespace member; you can add more SFINAE checks to it if appropriate.
Your issue boils down to that the language allows at most one implicit conversion.
One solution would then be to make a function accepting bool_t as well:
number_t<n1 + n2> operator+(number_t<n1>, bool_t<n2>) {
//return something
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With