I'm trying to write a templated class which is essentially just a wrapper for other types for the sake of being able to easily watch things that are happening to the values - every time any operator, constructor, destructor, etc, is called. So I'm trying to make an operator bool() that works by calling operator bool() on any class that has one, static_cast on any class that doesn't have operator bool(). Classes that can't do either should only fail compilation if someone tries to convert to bool. I haven't focused on this part yet, as I'm stumped by this simpler case.
It compiles and works fine on MSVC 2015, but won't compiler on either Clang (3.8.1) or GCC (6.2). GCC and Clang are both set to -std=c++1z
Link to online compiler showing errors on GCC and Clang: https://godbolt.org/g/v3B6TE
This is a stripped down version that shows the issue:
#include <type_traits>
#include <utility>
#include <assert.h>
template <typename T>
struct Wrapper {
T val;
template<typename...Params>
Wrapper(Params&&...args): val(std::forward<Params>(args)...){}
/**
* \brief bool conversion operator
*/
template <typename = std::enable_if_t<std::is_fundamental<T>::value>>
operator bool() const {
return static_cast<bool>(val);
}
/**
* \brief bool conversion operator
*/
template <typename = std::enable_if_t<!std::is_fundamental<T>::value>, typename = void>
operator bool() const {
return val.operator bool();
}
};
struct HasOperatorBool {
mutable bool done{ false };
operator bool() const{
done = true;
return done;
}
};
int main(int argc, char** argv) {
Wrapper<HasOperatorBool> whob;
bool didIt = whob;
assert(didIt);
Wrapper<int> wi{1};
bool bi = wi;
assert(bi);
return 0;
}
Both clang and gcc are saying something about std::enable_if_t
having no type
:
gcc:
In file included from /tmp/gcc-explorer-compiler116910-70-16kehep/example.cpp:1:
/usr/lib/gcc/x86_64-linux-gnu/5.4.1/../../../../include/c++/5.4.1/type_traits:2388:44: error: no type named 'type' in 'std::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^~~~~
15 : note: in instantiation of template type alias 'enable_if_t' requested here
template <typename = std::enable_if_t<std::is_fundamental<T>::value>>
^
40 : note: in instantiation of template class 'Wrapper<HasOperatorBool>' requested here
Wrapper<HasOperatorBool> whob;
^
In file included from /tmp/gcc-explorer-compiler116910-70-16kehep/example.cpp:1:
/usr/lib/gcc/x86_64-linux-gnu/5.4.1/../../../../include/c++/5.4.1/type_traits:2388:44: error: no type named 'type' in 'std::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^~~~~
2 errors generated.
Compiler exited with result code 1
clang:
In file included from /tmp/gcc-explorer-compiler116910-70-1nlkefa/example.cpp:1:0:
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::is_fundamental<HasOperatorBool>::value; _Tp = void]':
16 : required from 'struct Wrapper<HasOperatorBool>'
40 : required from here
/opt/gcc-explorer/gcc-6.2.0/include/c++/6.2.0/type_traits:2512:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
I am perhaps interested in alternative approaches to this, but I'm very interested in the technical reason why this won't work with 2 of the 3 compilers. Are one or more of the compilers wrong? Is there a way to achieve what I want?