integral_constant vs constexpr - c++

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

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>();
};

Unable to discriminate template specialization with enable_if and is_base_of

I am trying to trade some run-time checks for compile-time checks to identify the base class of an object with template specializations.
The code compiles fine, but I can't figure out why the enable_if statement always end up invalid or equal to void because I'm always landing on the base template struct.
#include <iostream>
#include <type_traits>
using namespace std;
struct BaseOne {};
struct DerivedOne : BaseOne {};
struct BaseTwo {};
struct DerivedTwo : BaseTwo {};
struct Default {};
template<typename T, typename = void>
struct get_category_impl {
static constexpr int value = 0;
};
template<typename T>
struct get_category_impl<T, typename enable_if<is_base_of<BaseOne, T>::value, T>::type> {
static constexpr int value = 1;
};
template<typename T>
struct get_category_impl<T, typename enable_if<is_base_of<BaseTwo, T>::value, T>::type> {
static constexpr int value = 2;
};
template<typename T>
constexpr int get_category = get_category_impl<T>::value;
int main() {
cout << get_category<BaseOne> << "\n"; // prints 0
cout << get_category<DerivedOne> << "\n"; // prints 0
cout << get_category<BaseTwo> << "\n"; // prints 0
cout << get_category<DerivedTwo> << "\n"; // prints 0
cout << get_category<Default> << "\n"; // prints 0
}
The second parameter to enable_if doesn't need to be specified. If you do specify it, it needs to somehow resolve to void. Since you've specified the second parameter as T, this doesn't work.
Instead, just do this:
template<typename T>
struct get_category_impl<T, typename enable_if<is_base_of<BaseOne, T>::value>::type> {
// ^ No T
static constexpr int value = 1;
};
and similarly for the other specialization.
Here's a demo.

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..."

Partial class template specialisation for multiple types

I have a class which allows for a vector to be created holding any type or class. However I'd like to add additional functionality for numerical types.
template <>
class Vec<double> : public VecBase<double>
{
// == METHODS ==
public:
// -- Constructors & Destructors --
explicit Vec(const unsigned long long t_size);
virtual ~Vec();
// -- Operators --
friend Vec<double> operator+(const Vec<double>&, const double);
// -- Methods --
double sum();
... etc.
I have partially specialised the class template to allow overloading of mathematical operators for double specialisation. I'd now like to extend this specialisation to int as well, but rather than copy the specialisation replacing double with int, is there a way to add it into the specialisation list?
That is, is there any way to allow for:
template<>
class Vec<double (or) int>
Cheers!
I suppose you can use a boolean default value, like in foo struct in the following example
#include <iostream>
template <typename>
struct isSpecialType
{ static constexpr bool value { false }; };
template <>
struct isSpecialType<int>
{ static constexpr bool value { true }; };
template <>
struct isSpecialType<double>
{ static constexpr bool value { true }; };
template <typename T, bool = isSpecialType<T>::value>
struct foo;
template <typename T>
struct foo<T, true>
{ static constexpr bool value { true }; };
template <typename T>
struct foo<T, false>
{ static constexpr bool value { false }; };
int main()
{
std::cout << "- void value: " << foo<void>::value << std::endl;
std::cout << "- bool value: " << foo<bool>::value << std::endl;
std::cout << "- int value: " << foo<int>::value << std::endl;
std::cout << "- double value: " << foo<double>::value << std::endl;
}
The idea is define a sort of type traits (isSpecialType) to choose the selected types (int and double, in your example) with a booleand value that is false in the generic implementation and true in the specializations.
template <typename>
struct isSpecialType
{ static constexpr bool value { false }; };
template <>
struct isSpecialType<int>
{ static constexpr bool value { true }; };
template <>
struct isSpecialType<double>
{ static constexpr bool value { true }; };
Next you have to declare the foo struct (class Vec, in your question) with a supplemental bool template value with the isSpecialType<T>::value default value
template <typename T, bool = isSpecialType<T>::value>
struct foo;
Last, you have to implement two partially specialized version of foo: the first one with the boolean true value
template <typename T>
struct foo<T, true>
{ static constexpr bool value { true }; };
corresponding to the specialized version of your Vec; the one with the false boolean value
template <typename T>
struct foo<T, false>
{ static constexpr bool value { false }; };
corresponding to the generic version of your Vec.
Another point: my example is C++11 or newer code; if you want a C++98 version, you have only to define the bool values as const (instead constexpr) and initialize they whit the C++98 style; I mean
static bool const bool value = true;
instead of
static constexpr bool value { true };
There sure is but you might find this already done in http://en.cppreference.com/w/cpp/numeric/valarray
have a look at std::enable_if and std::is_integral and std::is_floating_point. (copied from cplusplus.com)
// enable_if example: two ways of using enable_if
#include <iostream>
#include <type_traits>
// 1. the return type (bool) is only valid if T is an integral type:
template <class T>
typename std::enable_if<std::is_integral<T>::value,bool>::type
is_odd (T i) {return bool(i%2);}
// 2. the second template argument is only valid if T is an integral type:
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}
int main() {
short int i = 1; // code does not compile if type of i is not integral
std::cout << std::boolalpha;
std::cout << "i is odd: " << is_odd(i) << std::endl;
std::cout << "i is even: " << is_even(i) << std::endl;
return 0;
}
I have same idea with #max66, but you can use a helper function to do this a bit easier.
#include <iostream>
#include <type_traits>
// helper
template <typename ...Ts>
struct allowed_types
{
template <typename T>
using check = std::disjunction<std::is_same<T, Ts>...>;
template <typename T>
inline static constexpr bool check_v = check<T>::value;
};
// usage
template <typename T, bool = allowed_types<double, float>::check_v<T>>
struct foo;
template <typename T>
struct foo<T, true> // for double and float
{
inline static constexpr size_t value = 1;
};
template <typename T>
struct foo<T, false> // for other types
{
inline static constexpr size_t value = 2;
};
int main()
{
std::cout << foo<float>::value << '\n'; // 1
std::cout << foo<double>::value << '\n'; // 1
std::cout << foo<int>::value << '\n'; // 2
std::cout << foo<char>::value << '\n'; // 2
}
Just put any set of types you need.
For example:
template <typename T, bool = allowed_types<char, int, std::vector<int>>::check_v<T>>
EDIT:
If you need to split your specializations more than on 2 groups, then you need to use enable_if approach.
With helper from above it could be written like this:
// default, for any type
template <typename T, typename = void>
struct foo
{
inline static constexpr size_t value = 1;
};
// for double and float
template <typename T>
struct foo<T, std::enable_if_t<allowed_types<double, float>::check_v<T>>>
{
inline static constexpr size_t value = 2;
};
// for int and char
template <typename T>
struct foo<T, std::enable_if_t<allowed_types<int, char>::check_v<T>>>
{
inline static constexpr size_t value = 3;
};
int main()
{
std::cout << foo<bool>::value << '\n'; // 1
std::cout << foo<double>::value << '\n'; // 2
std::cout << foo<float>::value << '\n'; // 2
std::cout << foo<int>::value << '\n'; // 3
std::cout << foo<char>::value << '\n'; // 3
}

How to use SFINAE for enum without specifying the enum?

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
{};