I have different view types, which each have a std::size_t View::dimension
member constant, and a typename View::value_type
member type.
The following compile-type check should verify if both From
and To
are views (verified using is_view<>
), and the content of From
can be assigned to To
. (same dimensions, and convertible value types).
template<typename From, typename To>
struct is_compatible_view : std::integral_constant<bool,
is_view<From>::value &&
is_view<To>::value &&
From::dimension == To::dimension &&
std::is_convertible<typename From::value_type, typename To::value_type>::value
> { };
is_view<T>
is such that it always evaluates to std::true_type
or std::false_type
, for any type T
. The problem is that if From
or To
is not a view type, then From::dimension
(for example) may not exist, and is_compatible_view<From, To>
causes a compilation error.
It should instead evaluate to std::false_type
in this case.
is_compatible_view
is used for SFINAE with std::enable_if
, to disable member functions. For example a view class can have a member function
struct View {
constexpr static std::size_t dimension = ...
using value_type = ...
template<typename Other_view>
std::enable_if_t<is_compatible_view<Other_view, View>> assign_from(const Other_view&);
void assign_from(const Not_a_view&);
};
Not_a_view
is not a view, and causes a compilation error in is_compatible_view<Not_a_view, ...>
. When calling view.assign_from(Not_a_view())
, SFINAE does not apply, and instead a compilation error occurs when the compiler tries to resolve the first assign_from
function.
How can is_compatible_view
be written such that this works correctly? In C++17 does std::conjunction<...>
allow this?
One approach is using something like
std::conditional
to delay evaluation of some parts of your type trait until we've verified that other parts of your type trait are already true.That is:
Note that I'm using both
conditional_t
and::type
.is_compatible_view_details
will only be instantiated if bothFrom
andTo
are views.A similar approach would be to use
std::conjunction
with the above, which because of short-circuiting will similarly delay evaluation:Either way, you need to pull out the details.
A third approach would be to use
enable_if_t
as a specialization:Here, if any of the expressions in the
enable_if_t
are ill-formed, SFINAE kicks in and we just use the primary template, which isfalse_type
.