Hi,
Nice library; I'm having some real issues though with a container type. I'm using FixedVector from the fixed-containers library. The underlying storage has a fixed size, so tuple_size_v is well-defined and is 0 on this type. Therefore, the print formatter is resolving it as an empty tuple, and printing out {}, instead of a std-compatible container and iterating over the elements.
What has my head completely spinning though, is that the iterator functions are well-defined and working on it, but the trait for if it's a range is false. I have compared it side-by-side with std::vector:
using FixedVector = fixed_containers::FixedVector<int, 16>;
using ComparisonFixed = decltype(begin(std::declval<FixedVector const &>()) != end(std::declval<FixedVector const &>()));
using ComparisonStd = decltype(begin(std::declval<std::vector<int> const &>()) != end(std::declval<std::vector<int> const &>()));
static_assert(std::is_same_v<ComparisonFixed, double>, "Fixed type of inequality comparison");
static_assert(std::is_same_v<ComparisonStd , double>, "std type of inequality comparison");
// both are printed as bool.
// debug.hpp:1055:15: error: static assertion failed due to requirement 'std::is_same_v<bool, double>': Fixed type of inequality comparison
// 1055 | static_assert(std::is_same_v<ComparisonFixed, double>, "Fixed type of inequality comparison");
// | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// debug.hpp:1056:15: error: static assertion failed due to requirement 'std::is_same_v<bool, double>': std type of inequality comparison
// 1056 | static_assert(std::is_same_v<ComparisonStd , double>, "std type of inequality comparison");
// | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using VoidFixed = typename debug_void<ComparisonFixed>::type;
using VoidStd = typename debug_void<ComparisonStd >::type;
static_assert(std::is_same_v<VoidFixed, double>, "Fixed type of debug_void of decltype of comparison");
static_assert(std::is_same_v<VoidStd , double>, "std type of debug_void of decltype of comparison");
// Both are void
// debug.hpp:1062:15: error: static assertion failed due to requirement 'std::is_same_v<void, double>': Fixed type of debug_void of decltype of comparison
// 1062 | static_assert(std::is_same_v<VoidFixed, double>, "Fixed type of debug_void of decltype of comparison");
// | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// debug.hpp:1063:15: error: static assertion failed due to requirement 'std::is_same_v<void, double>': std type of debug_void of decltype of comparison
// 1063 | static_assert(std::is_same_v<VoidStd , double>, "std type of debug_void of decltype of comparison");
static_assert(is_same_v<decltype(debug_cond_is_range<FixedVector >::value), double>, "Fixed type of trait requirement");
static_assert(is_same_v<decltype(debug_cond_is_range<std::vector<int>>::value), double>, "std type of trait requirement");
// debug.hpp:1066:15: error: static assertion failed due to requirement 'is_same_v<const bool, double>': Fixed type of trait requirement
// 1066 | static_assert(is_same_v<decltype(debug_cond_is_range<FixedVector >::value), double>, "Fixed type of trait requirement");
// | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// debug.hpp:1067:15: error: static assertion failed due to requirement 'is_same_v<const bool, double>': std type of trait requirement
// 1067 | static_assert(is_same_v<decltype(debug_cond_is_range<std::vector<int>>::value), double>, "std type of trait requirement");
//
static_assert(debug_cond_is_range<FixedVector >::value == 999, "Fixed is a range");
static_assert(debug_cond_is_range<std::vector<int>>::value == 999, "std is a range");
// And now one is true, and the other false.
I'm really struggling to folow the logic of what's meant to happen here.
debug_cond_is_range expands to
template <class T, class = void> struct debug_cond_is_range : std::false_type {};
template <class T> struct debug_cond_is_range<
T,
typename debug_void<
decltype( begin(std::declval<T const &>()) != end(std::declval<T const &>()) )
>::type
> : std::true_type {};
which surely means that if debug_void<....>::type exists on both of them, the true_type version is well-defined and selected. Both are debug_cond_is_range<T, void>, yet evidently true_type is being selected for the std::vector and false_type for the FixedVector. All whilst both have bool as the type of the iterator comparison, and both have void as the nested type.
If the traits ultimately have to be specialised, I think it'd be much clearer simply to use a boolean non-type argument rather than inheriting from bool_constant. Or some clarification on what should be expected, because defaulting to void and also using it as a nested type adds some confusion. void to me indicates a failure to expand something, and so should be falsey, yet it seems it's being used as the nested type to denote success in resolving the type of the iterator comparison and so is truthy.
Or, using constraints would ideally be much more readable, but I understand this would force C++20 support and so may not be acceptable.
But, is this as expected? Admittedly I'm going a bit screen-blind right now, but I'm struggling to see how the compiler is able to select a different specialisation when the comparison is well-defined and thus debug_void<....>::type is defined for both cases.
I also did this directly in the header file at the print specialisation - just in case there's some name lookup issue. Are begin/end custom, or did the std:: get missed off? I don't see a definition in the header file so that seems a potential point of difference, but still not following how they are both deduced as bool. I am using the xmake package, so on #ec10419.
Thanks!
Hi,
Nice library; I'm having some real issues though with a container type. I'm using FixedVector from the fixed-containers library. The underlying storage has a fixed size, so
tuple_size_vis well-defined and is 0 on this type. Therefore, the print formatter is resolving it as an empty tuple, and printing out{}, instead of a std-compatible container and iterating over the elements.What has my head completely spinning though, is that the iterator functions are well-defined and working on it, but the trait for if it's a range is false. I have compared it side-by-side with std::vector:
I'm really struggling to folow the logic of what's meant to happen here.
debug_cond_is_rangeexpands towhich surely means that if debug_void<....>::type exists on both of them, the true_type version is well-defined and selected. Both are
debug_cond_is_range<T, void>, yet evidently true_type is being selected for the std::vector and false_type for the FixedVector. All whilst both have bool as the type of the iterator comparison, and both have void as the nested type.If the traits ultimately have to be specialised, I think it'd be much clearer simply to use a boolean non-type argument rather than inheriting from bool_constant. Or some clarification on what should be expected, because defaulting to void and also using it as a nested type adds some confusion. void to me indicates a failure to expand something, and so should be falsey, yet it seems it's being used as the nested type to denote success in resolving the type of the iterator comparison and so is truthy.
Or, using constraints would ideally be much more readable, but I understand this would force C++20 support and so may not be acceptable.
But, is this as expected? Admittedly I'm going a bit screen-blind right now, but I'm struggling to see how the compiler is able to select a different specialisation when the comparison is well-defined and thus debug_void<....>::type is defined for both cases.
I also did this directly in the header file at the print specialisation - just in case there's some name lookup issue. Are begin/end custom, or did the std:: get missed off? I don't see a definition in the header file so that seems a potential point of difference, but still not following how they are both deduced as bool. I am using the xmake package, so on #ec10419.
Thanks!