TL;DR: I am looking for a C++14 equivalent of the following C++20 MWE:
template<int sz>
struct bits {
int v; // note explicit(expr) below
explicit(sz > 1) operator bool() const { return bool(v); }
};
int main() {
bool c = bits<1>{1}; // Should work
bool d = bits<3>{1}; // Should fail
}
Context:
We have a C++ class bits<sz> representing bitvectors of length sz. Conversion to bool used to be implicit for all sz, but this proved to be error-prone, so we changed operator bool() to be explicit.
However, 1-bit bitvectors are (in our context) almost-completely equivalent to Booleans, so it would be desirable for operator bool() to be implicit when sz == 1.
This can be achieved with explicit(sz > 1) in C++20, but we are targeting C++14.
I tried to overload the operator for sz == 1, but it seems that the explicit qualifier applies to it as well: the following does not work.
template<int sz>
struct bits {
int v;
explicit operator bool() const { return bool(v); }
};
template<> bits<1>::operator bool() const {
return bool(v);
}
int main() {
bool c = bits<1>{1}; // Fails: "No viable conversion"
}
Hence the question: How can I specify in C++14 that operator bool() should be explicit only for sz > 1?
I'm including some background below for curious readers.
Background:
This problem came up in the context of an embedded domain-specific language in C++. One of the business requirements is that operator== returns a bit<1>, not a bool. This is working smoothly with GNU's libstdc++, but we're running into trouble with that requirement on macOS because libstdc++ there implements operator== on std::array using the version of std::equal that takes a predicate, and implements that predicate using a struct whose operator() returns bool with body a == b (which in our case returns a bits<1>, causing a conversion error).
To make it concrete for curious readers, the following program compiles fine on GNU, but not on macOS, because of the way operator== on std::array is implemented:
#include <array>
struct S { explicit operator bool() const { return true; } };
struct T {};
S operator==(T, T) { return S(); }
int main() {
std::array<T, 1> arr = { T() };
return arr == arr;
}
That's because deep down in the implementation of == on arrays GNU libstdc++ has a test if (!(*it1 == *it2)), which invokes the explicit operator bool() on S without trouble, where as on macOS the library uses if (!__pred(*it1, *it2)) with __pred roughly equivalent to bool __pred(S a, S b) { return a == b; }, which doesn't typecheck.