I'm currently porting my library, but my dark template magic won't get compiled with GCC 5.3
template<typename vreal =
std::enable_if<std::is_vreal<vreal>::value,
floatType>::type>
inline vreal foo(vreal bar)
{
return bar;
}
template<typename vreal =
std::enable_if<std::is_vreal<vreal>::value,
floatType>::type>
struct bar { vreal i; };
GCC complains about "vreal was not defined in current scope (WTF?)"
Rewrite the upper template fragment to
template<typename vreal,
typename enable = typename std::enable_if<std::is_vreal<vreal>::value != 0>::type>
But this doesn't work either. It breaks much much later in the code and I assume that it's due the introduction of the additional template param.
Also, I don't understand why I had to introduce the comparison with 0. Without it gcc complained about missing 'type' on enabled_if.
So, the main question is: how to get the same SFINAE logic (compile ONLY if the argument is vreal) WITHOUT additional arguments.
I could rewrite that to return type SFINAE - but that would be a lot of work which I'd like to avoid (differentiating between functions, classes, structs, typedefs / usings...) even though it's wrapped in a macro.
template<typename vreal>
typename std::enable_if<is_vreal<vreal>, vreal>::type inline vreal .....
This is not valid C++:
template<typename vreal =
std::enable_if<std::is_vreal<vreal>::value,
floatType>::type>
inline vreal foo(vreal bar)
{
return bar;
}
for many reasons. It uses a symbol in std
that isn't in std
(is_vreal
), which means your program is ill-formed. It uses a token floatType
that is not defined (you did post a [MCVE] right?). It uses vreal
before it is in scope, in the definition of vreal
.
I have no idea what it is supposed to mean, other than your seeming belief that it does SFINAE magic: it states that if vreal
passes the is_vreal
test, it should be the type floatType
by default. But in order to reach this point, you had to have the type vreal
already, so the default type doesn't seem to matter.
Also, ::type
is not a type in a dependent context:, so std::enable_if<std::is_vreal<vreal>::value, floatType>::type
should complain that you are using a non-type named ::type
in a context where a type is expected. You need to do typenam estd::enable_if<std::is_vreal<vreal>::value, floatType>::type
.
You seem to also state that you are using macros to generate code. That was a poor decision.
As far as I can tell, simply removing the enable_if
clause completely will solve your problem for most cases.
The exception is for functions, because there can be overloads, you can introduce a SFINAE helper.
Ditch the macro completely. Class and function templates work significantly differently anyhow.
For classes/structs:
template<class vreal>
struct bar { vreal i; };
because there really isn't another alternative -- there isn't the concept of overloading with structures/classes like there is with functions.
For functions, we want a SFINAE test so we can overload:
template<class T, class R=T>
using vreal_test = typename
std::enable_if<std::is_vreal<T>::value, R>::type
template<class vreal>
inline vreal_test<vreal> foo(vreal bar)
{
return bar;
}
if the function returns a differnet type, do
template<class vreal>
inline vreal_test<vreal,void> foo2(vreal bar)
{
return;
}
You can do this as you sweep to remove your macro.