How to use SFINAE for enum without specifying the enum? - c++

Using answer from
Substitution failure is not an error (SFINAE) for enum I tried to write a code that would get enum value from a class, and if this enum value is not found it would have a fallback value.
As I'm beginner with templates, after couple of hours I gave up and found a "solution" using macros :(
Is there a way to do the same thing without macros and without copying the code for every possible enum value?
This is what I came up with:
struct foo
{
enum FooFields
{
enumFoo,
enumHehe
};
};
struct bar
{
enum BarFields
{
enumHehe = 2
};
};
#define GETENUM_DEF(testedEnum) \
template<class T> \
struct get_ ## testedEnum{\
typedef char yes;\
typedef yes (&no)[2];\
\
template<int>\
struct test2;\
\
template<class U>\
static int test(test2<U::testedEnum>*){return U::testedEnum;};\
template<class U>\
static int test(...){return -1;};\
\
static int value(){return test<T>(0);}\
};
GETENUM_DEF(enumFoo)
GETENUM_DEF(enumHehe)
int main() {
std::cout<<get_enumFoo<foo>::value()<<std::endl; //returns 0;
std::cout<<get_enumFoo<bar>::value()<<std::endl; //returns -1;
std::cout<<get_enumHehe<foo>::value()<<std::endl; //returns 1;
std::cout<<get_enumHehe<bar>::value()<<std::endl; //returns 2;
return 0;
}

C++ requires that you define a get_someField for every field you want to get, but you'd have to do that with or without macros.
Playing with SFINAE is part of what is known as template meta-programming. What you are doing is effectively detecting whether the expression T::enumFoo is valid, and returning that value if it is, else -1.
To detect whether expression is valid, we can do something like this:
#include <type_traits>
// You need void_t to avoid a warning about the lhs of the comma operator
// having no effect. C++ 17 has std::void_t
template<class...> using void_t = void;
template<class T, class = void>
struct get_enumFoo
{
static constexpr int value = -1;
};
template<class T>
struct get_enumFoo<T, void_t<decltype(T::enumFoo)>>
{
static constexpr int value = T::enumFoo;
};
template<class T, class = void>
struct get_enumHehe
{
static constexpr int value = -1;
};
template<class T>
struct get_enumHehe<T, void_t<decltype(T::enumHehe)>>
{
static constexpr int value = T::enumHehe;
};
Using it (your example):
#include <iostream>
int main() {
std::cout << get_enumFoo<foo>::value << std::endl; //returns 0;
std::cout << get_enumFoo<bar>::value << std::endl; //returns -1;
std::cout << get_enumHehe<foo>::value << std::endl; //returns 1;
std::cout << get_enumHehe<bar>::value << std::endl; //returns 2;
}
It works as follows:
We define a case for SFINAE to fall back on in the case that the expression T::enumFoo is invalid:
template<class T, class = void>
struct get_enumFoo
{
static constexpr int value = -1;
};
We then define the case that sees if T::enumFoo is valid:
template<class T>
struct get_enumFoo<T, void_t<decltype(T::enumFoo)>>
{
static constexpr int value = T::enumFoo;
};
If T::enumFoo is invalid, then the decltype(T::enumFoo) is an invalid expression, so SFINAE kicks in and we fall back to our previous case.
If T::enumFoo is valid, then decltype(T::enumFoo) is some type, but void_t<decltype(T::enumFoo)> is void. So we are specializing get_enumFoo<T, void> to have the field value = T::enumFoo.
Try it online
To further reduce the boilerplate behind adding new get_field traits, you could define a base class:
namespace detail {
struct get_foo_defaultValue
{
static constexpr int value = -1;
};
}
Then the base case would be
template<class T, class = void>
struct get_enumFoo
: detail::get_foo_defaultValue
{};

Related

Declare a constexpr static member that is a function of a potentially-absent member in a template parameter?

I have a templated class for which I would like to provide a constexpr integer whose value is determined by the presence or absence of a constexpr integer in the template parameter:
template<typename Traits>
class Foo
{
static constexpr int MaxDegree =
std::conditional<
std::is_integral<Traits::MaxDegree>::value,
std::integral_constant<int, Traits::MaxDegree>,
std::integral_constant<int, 0>
>::value;
};
struct TraitA { };
struct TraitB { constexpr static int MaxDegree = 1; };
int main()
{
std::cout
<< Foo<TraitA>::MaxDegree /* should be 0 */ << " "
<< Foo<TraitB>::MaxDegree; /* should be TraitB::MaxDegree == 1 */
<< "\n";
}
Obviously, this doesn't work since std::is_integral fails for TraitA. Is there anything that will work?
I'm constrained to c++11.
Traits::MaxDegree
yields a compiler error, if the member doesn't exist. This means you cannot use this code as part of the expression directly.
You could use constexpr functions with SFINAE to implement this though:
template<class T>
constexpr typename std::enable_if<std::is_integral<decltype(T::MaxDegree)>::value, int>::type GetMaxDegree()
{
return T::MaxDegree;
}
template<class T>
constexpr int GetMaxDegree(...) // this one is only used, if the first version results in a substitution failure
{
return 0;
}
template<typename Traits>
class Foo
{
public:
static constexpr int MaxDegree = GetMaxDegree<Traits>();
};

How to check for static member variable template?

I need to define a class, foo, with a static member variable template, foo::static_variable_template<T>. This member should only exist when T fulfills certain requirements. For example, when the constexpr static function T::constexpr_static_function() exists. Otherwise, foo::static_variable_template<T> should not exist. Moreover, I would like to be able to test for the existence of foo::static_variable_template<T> at compile-time via SFINAE.
Here is an approximation of what I would like to do:
#include <iostream>
struct foo
{
template<class T>
static constexpr int static_variable_template =
T::constexpr_static_function();
// XXX this works but requires a second defaulted template parameter
// template<class T, int = T::constexpr_static_function()>
// static constexpr int static_variable_template =
// T::constexpr_static_function();
};
struct has_constexpr_static_function
{
static constexpr int constexpr_static_function() { return 42; }
};
struct hasnt_constexpr_static_function
{
};
template<class T, class U,
int = T::template static_variable_template<U>>
void test_for_static_variable_template(int)
{
std::cout << "yes it has\n";
}
template<class T, class U>
void test_for_static_variable_template(...)
{
std::cout << "no it hasn't\n";
}
int main()
{
test_for_static_variable_template<foo, has_constexpr_static_function>(0);
test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}
This approximation nearly works, but only if foo::static_variable_template has a second, defaulted template parameter. Because this second parameter is an implementation detail, I'd like to hide it from the public interface of foo::static_variable_template.
Is this possible in C++17?
I am not sure if your intent is to initialise foo::static_variable_template with 0 if T::constexpr_static_function() is missing or you want to disable it entirely. In case of the former, this might be useful. For example, this (clunky) solution works (requires C++17 for if constexpr; note that your variable is now a function):
#include <iostream>
template <typename T>
class has_func
{
typedef char does;
typedef long doesnt;
template <typename C> static does test( decltype(&C::constexpr_static_function) );
template <typename C> static doesnt test(...);
public:
static constexpr bool value()
{
return sizeof(test<T>(0)) == sizeof(char);
}
};
struct foo
{
template<class T>
static constexpr int static_variable_template()
{
if constexpr (has_func<T>::value())
{
return T::constexpr_static_function();
}
return 0;
}
// XXX this works but requires a second defaulted template parameter
// template<class T, int = T::constexpr_static_function()>
// static constexpr int static_variable_template =
// T::constexpr_static_function();
};
struct has_constexpr_static_function
{
static constexpr int constexpr_static_function() { return 42; }
};
struct hasnt_constexpr_static_function
{
};
template<class T, class U>
void test_for_static_variable_template(...)
{
if constexpr (has_func<U>::value())
{
std::cout << "yes it has\n";
}
else
{
std::cout << "no it hasn't\n";
}
}
int main()
{
std::cout << foo::static_variable_template<has_constexpr_static_function>() << "\n";
std::cout << foo::static_variable_template<hasnt_constexpr_static_function>() << "\n";
/// Original test
test_for_static_variable_template<foo, has_constexpr_static_function>(0);
test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}
Prints
42
0
yes it has
no it hasn't
Tested with clang 5.0.1.
In case you want to disable foo::static_variable_template entirely, you might need to use std::enable_if:
#include <iostream>
template <typename T>
class has_func
{
typedef char does;
typedef long doesnt;
template <typename C> static does test( decltype(&C::constexpr_static_function) );
template <typename C> static doesnt test(...);
public:
static constexpr bool value()
{
return sizeof(test<T>(0)) == sizeof(char);
}
};
struct foo
{
template<class T, typename std::enable_if<has_func<T>::value()>::type ...>
static constexpr int static_variable_template()
{
if constexpr (has_func<T>::value())
{
return T::constexpr_static_function();
}
return 0;
}
// XXX this works but requires a second defaulted template parameter
// template<class T, int = T::constexpr_static_function()>
// static constexpr int static_variable_template =
// T::constexpr_static_function();
};
struct has_constexpr_static_function
{
static constexpr int constexpr_static_function() { return 42; }
};
struct hasnt_constexpr_static_function
{
};
template<class T, class U>
void test_for_static_variable_template(...)
{
if constexpr (has_func<U>::value())
{
std::cout << "yes it has\n";
}
else
{
std::cout << "no it hasn't\n";
}
}
int main()
{
std::cout << foo::static_variable_template<has_constexpr_static_function>() << "\n";
// We can't print this because it doesn't exist.
// std::cout << foo::static_variable_template<hasnt_constexpr_static_function>() << "\n";
/// Original test
test_for_static_variable_template<foo, has_constexpr_static_function>(0);
test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}
In this line of thought, I am not sure if you can disable a static template variable with std::enable_if. To quote the great Riemann, "I have for the time being, after some fleeting vain attempts, provisionally put aside the search for this..."

integral_constant vs constexpr

Could you please explain, why integral_constant and constexpr approaches in the following example result in different behaviours?
#include <iostream>
using namespace std;
struct Logger
{
// template<typename Type>
// using IsRawString =
// std::integral_constant<bool, std::is_same<const char*, Type>::value || std::is_same<char*, Type>::value>;
template<typename Type>
constexpr bool IsRawString()
{
return std::is_same<const char*, Type>::value || std::is_same<char*, Type>::value;
}
template<typename Type, typename Enable = void>
struct Traits
{
static const int Index = 1;
};
template<typename Type>
struct Traits<Type, std::enable_if_t<IsRawString<Type>()>>
{
static const int Index = 2;
};
template<typename Type>
struct Traits<Type, std::enable_if_t<std::is_pointer<Type>::value && !IsRawString<Type>()>>
{
static const int Index = 3;
};
};
int main()
{
cout << Logger::Traits<int>::Index << endl
<< Logger::Traits<char*>::Index << endl
<< Logger::Traits<const char*>::Index << endl
<< Logger::Traits<void*>::Index << endl;
return 0;
}
integral_constant approach https://ideone.com/WQy71r:
1
2
2
3
constexpr approach https://ideone.com/wPiM1m:
1
1
1
1
If I remove Logger struct and use Traits from the global scope, both approaches give the same result as for integral_constant inside struct (https://ideone.com/WGVuXE https://ideone.com/OpTbDm).
It happens because your IsRawString() declared as non static and it require class object for to be called.
When compiler try to generate Logger::Traits<char*>::Index and Logger::Traits<const char*>::Index it use SFINAE(http://en.cppreference.com/w/cpp/language/sfinae) and reject wrong variants with your constexpr function. The first Traits form with template<typename Type, typename Enable = void> generates only. Try declare IsRawString() as static member function

static_assert that a member variable is marked as 'static' in C++17?

I've been playing around with templates and would like to enforce that a template type given to a function has a particular static member. Unfortunately, there is no std::is_static type trait.
A rough example of how I would use it (or an alternative):
template<typename T>
void SomeFunc(T& obj)
{
static_assert(std::is_static_v<decltype(T::someVariable)>, "someVariable must be static");
}
Are there any ways to achieve this kind of behaviour? I could just write
template<typename T>
void SomeFunc(T& obj)
{
// must be static
T::someVariable;
}
But this wouldn't be anywhere near as nice or informative as a static_assert with a decent message. This is just a syntax error of sorts :(
Thanks!
If I understand correctly what you want, you're looking for std::is_member_pointer (or the opposite of the value of std::is_member_pointer).
An example (also C++11 and C++14 compliant)
#include <type_traits>
struct foo
{ int value; };
struct bar
{ static int value; };
int main()
{
static_assert(
true == std::is_member_pointer<decltype(&foo::value)>::value, "!");
static_assert(
false == std::is_member_pointer<decltype(&bar::value)>::value, "!!");
}
-- EDIT --
Not sure to understand the nakiya's objection but ... in the following example I've developed a type traits (hasSomeValueStatic) that set value to true if the template argument has a someValue static member and false otherwhise (if someValue isn't static of there isn't someValue.
#include <iostream>
#include <type_traits>
struct foo
{ int someValue; };
struct bar
{ static int someValue; };
template <typename, typename = int>
struct hasSomeValueStatic : std::false_type
{ };
template <typename T>
struct hasSomeValueStatic<T, decltype(T::someValue, 0)>
: std::integral_constant<bool,
! std::is_member_pointer<decltype(&T::someValue)>::value>
{ };
int main()
{
std::cout << hasSomeValueStatic<foo>::value << std::endl; // print 0
std::cout << hasSomeValueStatic<bar>::value << std::endl; // print 1
std::cout << hasSomeValueStatic<int>::value << std::endl; // print 0
}

How to detect whether there is actually a specific member variable in class?

I am purposely using the very same title as this question because I feel that the answer that was accepted does not account for a problem that I am stuck into.
I am looking for a way to detect if some class has some member variable. It is fundamental to note that I am looking for a variable, not a member function or anything else.
Here is the example provided in the question I linked:
template<typename T> struct HasX {
struct Fallback { int x; }; // introduce member name "x"
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
template<typename C> static char (&f(...))[2];
static bool const value = sizeof(f<Derived>(0)) == 2;
};
struct A { int x; };
struct B { int X; };
int main() {
std::cout << HasX<A>::value << std::endl; // 1
std::cout << HasX<B>::value << std::endl; // 0
}
But we will get the very same output if we do something like
template<typename T> struct HasX {
struct Fallback { int x; }; // introduce member name "x"
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
template<typename C> static char (&f(...))[2];
static bool const value = sizeof(f<Derived>(0)) == 2;
};
struct A {
void x()
{
}
};
struct B { int X; };
int main() {
std::cout << HasX<A>::value << std::endl; // 1
std::cout << HasX<B>::value << std::endl; // 0
}
(Please note that in the second example the int x in A was substituted with a member function void x()).
I have no real idea on how to work around this problem. I partially fixed this by doing something like
template <bool, typename> class my_helper_class;
template <typename ctype> class my_helper_class <true, ctype>
{
static bool const value = std :: is_member_object_pointer <decltype(&ctype :: x)> :: value;
};
template <typename ctype> class my_helper_class <false, ctype>
{
static bool const value = false;
};
template <typename T> struct HasX
{
// ...
static bool const value = my_helper_class <sizeof(f <Derived>(0)) == 2, T> :: value;
};
Which actually selects if I am using an object. However, the above doesn't work if there are more overloaded functions with the same name x in my class.
For example if I do
struct A
{
void x()
{
}
void x(int)
{
}
};
Then the pointer is not resolved successfully and the a call to HasX <A> doesn't compile.
What am I supposed to do? Is there any workaround or simpler way to get this done?
The problem is that HasX only checks if the name x exists. The ... gets selected if &C::x is ambiguous (which happens if it matches both in Fallback and T). The ChT<> overload gets selected only if &C::x is exactly Fallback::x. At no point are we actually checking the type of T::x - so we never actually check if x is a variable or function or whatever.
The solution is: use C++11 and just check that &T::x is a member object pointer:
template <class T, class = void>
struct HasX
: std::false_type
{ };
template <class T>
struct HasX<T,
std::enable_if_t<
std::is_member_object_pointer<decltype(&T::x)>::value>
>
: std::true_type { };
If &T::x doesn't exist, substitution failure and we fallback to the primary template and get false_type. If &T::x exists but is an overloaded name, substitution failure. If &T::x exists but is a non-overloaded function, substitution failure on enable_if_t<false>. SFINAE for the win.
That works for all of these types:
struct A {
void x()
{
}
void x(int)
{
}
};
struct B { int X; };
struct C { int x; };
struct D { char x; };
int main() {
static_assert(!HasX<A>::value, "!");
static_assert(!HasX<B>::value, "!");
static_assert(HasX<C>::value, "!");
static_assert(HasX<D>::value, "!");
}