c++ c99 template specialization with an Enum parameter without using integral_constant - c++

Basically, I am trying to use a enum which could do bit operations and there is a template function could map the enum element to array index. In the operator overload function I need
a compile-time constant expression.
I need something like integral_constant, but that is in c11 not in c99 anyone know how to implement integral_constant in c99?
OR
Any other ways to create the enum could performance bit operation and index an array?
Thanks~
enum E
{
E_a=1,
E_b=2,
E_c=4,
E_d=8,
E_MAX=16,
};
// Template struct to compute the index
template<int N>
struct I
{
static const int idx = 1 + I<N/2>::idx;
};
template<>struct I<1>{ static const int idx= 0; };
//
class Data
{
static void Init()
{
data[E_a].value = 10;
data[E_b].value = 20;
data[E_c].value = 40;
data[E_d].value = 80;
}
Data* operator[](const E& e)
{
return &(Data::data[I<e>::idx]); // <-Here is the problem, template parameter should be a constant expression but e is a parameter, even it is constant it is not a expression
}
// member variables
void* value;
static Data data[I<E_MAX>::idx];
};

Related

enum size and initialization of variable [duplicate]

Is there a way to convert an enum class field to the underlying type? I thought this would be automatic, but apparently not.
enum class my_fields : unsigned { field = 1 };
unsigned a = my_fields::field;
That assignment is being rejected by GCC. error: cannot convert 'my_fields' to 'unsigned int' in assignment.
I think you can use std::underlying_type to know the underlying type, and then use cast:
#include <type_traits> //for std::underlying_type
typedef std::underlying_type<my_fields>::type utype;
utype a = static_cast<utype>(my_fields::field);
With this, you don't have to assume the underlying type, or you don't have to mention it in the definition of the enum class like enum class my_fields : int { .... } or so.
You can even write a generic convert function that should be able to convert any enum class to its underlying integral type:
template<typename E>
constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
then use it:
auto value = to_integral(my_fields::field);
auto redValue = to_integral(Color::Red);//where Color is an enum class!
And since the function is declared to be constexpr, you can use it where constant expression is required:
int a[to_integral(my_fields::field)]; //declaring an array
std::array<int, to_integral(my_fields::field)> b; //better!
You cannot convert it implicitly, but an explicit cast is possible:
enum class my_fields : unsigned { field = 1 };
// ...
unsigned x = my_fields::field; // ERROR!
unsigned x = static_cast<unsigned>(my_fields::field); // OK
Also mind the fact, that the semicolon should be after the closed curly brace in your enum's definition, not before.
With C++23 you'll finally get a library function for this:
std::to_underlying
It is already implemented in the standard libraries of GCC 11, Clang 13, and MSVC 19.30 (aka 2022 17.0).
Until you're able to use C++23 I recommend you (re)name any custom implementation to to_underlying and place it between a #if !defined(__cpp_lib_to_underlying) #endif block, which is the associated feature test macro. This way you can simply ditch the code at some point in the future when C++23 becomes available for you.
As others have pointed out there is no implicit cast, but you can use an explicit static_cast. I use the following helper functions in my code to convert to and from an enum type and its underlying class.
template<typename EnumType>
constexpr inline decltype(auto) getIntegralEnumValue(EnumType enumValue)
{
static_assert(std::is_enum<EnumType>::value,"Enum type required");
using EnumValueType = std::underlying_type_t<EnumType>;
return static_cast<EnumValueType>(enumValue);
}
template<typename EnumType,typename IntegralType>
constexpr inline EnumType toEnum(IntegralType value)
{
static_assert(std::is_enum<EnumType>::value,"Enum type required");
static_assert(std::is_integral<IntegralType>::value, "Integer required");
return static_cast<EnumType>(value);
}
template<typename EnumType,typename UnaryFunction>
constexpr inline void setIntegralEnumValue(EnumType& enumValue, UnaryFunction integralWritingFunction)
{
// Since using reinterpret_cast on reference to underlying enum type is UB must declare underlying type value and write to it and then cast it to enum type
// See discussion on https://stackoverflow.com/questions/19476818/is-it-safe-to-reinterpret-cast-an-enum-class-variable-to-a-reference-of-the-unde
static_assert(std::is_enum<EnumType>::value,"Enum type required");
auto enumIntegralValue = getIntegralEnumValue(enumValue);
integralWritingFunction(enumIntegralValue);
enumValue = toEnum<EnumType>(enumIntegralValue);
}
Usage code
enum class MyEnum {
first = 1,
second
};
MyEnum myEnum = MyEnum::first;
std::cout << getIntegralEnumValue(myEnum); // prints 1
MyEnum convertedEnum = toEnum(1);
setIntegralEnumValue(convertedEnum,[](auto& integralValue) { ++integralValue; });
std::cout << getIntegralEnumValue(convertedEnum); // prints 2
I find the following function underlying_cast useful when having to serialise enum values correctly.
namespace util
{
namespace detail
{
template <typename E>
using UnderlyingType = typename std::underlying_type<E>::type;
template <typename E>
using EnumTypesOnly = typename std::enable_if<std::is_enum<E>::value, E>::type;
} // namespace util.detail
template <typename E, typename = detail::EnumTypesOnly<E>>
constexpr detail::UnderlyingType<E> underlying_cast(E e) {
return static_cast<detail::UnderlyingType<E>>(e);
}
} // namespace util
enum SomeEnum : uint16_t { A, B };
void write(SomeEnum /*e*/) {
std::cout << "SomeEnum!\n";
}
void write(uint16_t /*v*/) {
std::cout << "uint16_t!\n";
}
int main(int argc, char* argv[]) {
SomeEnum e = B;
write(util::underlying_cast(e));
return 0;
}

Retrieving the underlying type of a c++11 enum [duplicate]

Is there a way to convert an enum class field to the underlying type? I thought this would be automatic, but apparently not.
enum class my_fields : unsigned { field = 1 };
unsigned a = my_fields::field;
That assignment is being rejected by GCC. error: cannot convert 'my_fields' to 'unsigned int' in assignment.
I think you can use std::underlying_type to know the underlying type, and then use cast:
#include <type_traits> //for std::underlying_type
typedef std::underlying_type<my_fields>::type utype;
utype a = static_cast<utype>(my_fields::field);
With this, you don't have to assume the underlying type, or you don't have to mention it in the definition of the enum class like enum class my_fields : int { .... } or so.
You can even write a generic convert function that should be able to convert any enum class to its underlying integral type:
template<typename E>
constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
then use it:
auto value = to_integral(my_fields::field);
auto redValue = to_integral(Color::Red);//where Color is an enum class!
And since the function is declared to be constexpr, you can use it where constant expression is required:
int a[to_integral(my_fields::field)]; //declaring an array
std::array<int, to_integral(my_fields::field)> b; //better!
You cannot convert it implicitly, but an explicit cast is possible:
enum class my_fields : unsigned { field = 1 };
// ...
unsigned x = my_fields::field; // ERROR!
unsigned x = static_cast<unsigned>(my_fields::field); // OK
Also mind the fact, that the semicolon should be after the closed curly brace in your enum's definition, not before.
With C++23 you'll finally get a library function for this:
std::to_underlying
It is already implemented in the standard libraries of GCC 11, Clang 13, and MSVC 19.30 (aka 2022 17.0).
Until you're able to use C++23 I recommend you (re)name any custom implementation to to_underlying and place it between a #if !defined(__cpp_lib_to_underlying) #endif block, which is the associated feature test macro. This way you can simply ditch the code at some point in the future when C++23 becomes available for you.
As others have pointed out there is no implicit cast, but you can use an explicit static_cast. I use the following helper functions in my code to convert to and from an enum type and its underlying class.
template<typename EnumType>
constexpr inline decltype(auto) getIntegralEnumValue(EnumType enumValue)
{
static_assert(std::is_enum<EnumType>::value,"Enum type required");
using EnumValueType = std::underlying_type_t<EnumType>;
return static_cast<EnumValueType>(enumValue);
}
template<typename EnumType,typename IntegralType>
constexpr inline EnumType toEnum(IntegralType value)
{
static_assert(std::is_enum<EnumType>::value,"Enum type required");
static_assert(std::is_integral<IntegralType>::value, "Integer required");
return static_cast<EnumType>(value);
}
template<typename EnumType,typename UnaryFunction>
constexpr inline void setIntegralEnumValue(EnumType& enumValue, UnaryFunction integralWritingFunction)
{
// Since using reinterpret_cast on reference to underlying enum type is UB must declare underlying type value and write to it and then cast it to enum type
// See discussion on https://stackoverflow.com/questions/19476818/is-it-safe-to-reinterpret-cast-an-enum-class-variable-to-a-reference-of-the-unde
static_assert(std::is_enum<EnumType>::value,"Enum type required");
auto enumIntegralValue = getIntegralEnumValue(enumValue);
integralWritingFunction(enumIntegralValue);
enumValue = toEnum<EnumType>(enumIntegralValue);
}
Usage code
enum class MyEnum {
first = 1,
second
};
MyEnum myEnum = MyEnum::first;
std::cout << getIntegralEnumValue(myEnum); // prints 1
MyEnum convertedEnum = toEnum(1);
setIntegralEnumValue(convertedEnum,[](auto& integralValue) { ++integralValue; });
std::cout << getIntegralEnumValue(convertedEnum); // prints 2
I find the following function underlying_cast useful when having to serialise enum values correctly.
namespace util
{
namespace detail
{
template <typename E>
using UnderlyingType = typename std::underlying_type<E>::type;
template <typename E>
using EnumTypesOnly = typename std::enable_if<std::is_enum<E>::value, E>::type;
} // namespace util.detail
template <typename E, typename = detail::EnumTypesOnly<E>>
constexpr detail::UnderlyingType<E> underlying_cast(E e) {
return static_cast<detail::UnderlyingType<E>>(e);
}
} // namespace util
enum SomeEnum : uint16_t { A, B };
void write(SomeEnum /*e*/) {
std::cout << "SomeEnum!\n";
}
void write(uint16_t /*v*/) {
std::cout << "uint16_t!\n";
}
int main(int argc, char* argv[]) {
SomeEnum e = B;
write(util::underlying_cast(e));
return 0;
}

Error initializing array size using const static variable of class template

template<typename T, typename C = vector<T>>
class stack{
...
friend class stack_array;
};
template<typename T, typename C = vector<T>, typename K = stack<T,C>>
class stack_array{
...
static const size_t max_elem;
array<K, max_elem> store;
...
};
template<typename T, typename C = vector<T>, typename K = stack<T,C>>
const size_t stack_array<T,C,K>::max_elem = 10;
I get the following compilation error for the above:
error: the value of ‘stack_array<T, C, K>::max_elem’ is not usable in a constant expression
array<K, max_elem> store;
^
note: ‘stack_array<T, C, K>::max_elem’ was not initialized with a constant expression
static const size_t max_elem;
I presume this error occurs since the static const variable max_elem is initialized after the template class definition. Is this understanding correct?
Is there a way to resolve this error without necessarily changing the current usage of max_elem?
I 'd say to initialize the static member right in place.
static const size_t max_elem = 10;
More here.
Constant static members If a static data member of integral or
enumeration type is declared const (and not volatile), it can be
initialized with an initializer in which every expression is a
constant expression, right inside the class definition:
struct X {
const static int n = 1;
const static int m{2}; // since C++11
const static int k; };
const int X::k = 3; // Only this needs to be defined

How to initialize a member array in a template

I would like to have an array which has a length that depends on the parameter of my template, but I keep getting the "expected constant expression" error.
enum MyEnum
{
FIRST,
OTHER
};
template<MyEnum e>
struct MyTemplate
{
static const int arrSize;
int myArr[arrSize]; // error C2057: expected constant expression
// int myArr[e == FIRST ? 4 : 10]; // works, but isn't very readable...
};
template<>
const int MyTemplate<FIRST>::arrSize = 4;
template<>
const int MyTemplate<OTHER>::arrSize = 10;
The compiler I must use does not support constexpr, or any other C++ 11 features, and I also cannot pass the array size as a template parameter.
edit: I also must not use new.
Thanks
In some cases like this, I'll add a function get_array_size<e>(). Since you say you don't have constexpr, there's still decent possibilities:
//I call this a pseudo-template-function, but there's probably better names
template<MyEnum> struct GetArraySize; //compiler error for default
template<> struct GetArraySize<FIRST> {static const int value=4;};
template<> struct GetArraySize<OTHER> {static const int value=10;};
template<MyEnum e>
struct MyTemplate
{
static const int arrSize = GetArraySize<e>::value;
int myArr[arrSize];
};
http://coliru.stacked-crooked.com/a/f03a5fa94a038892
Are we reinventing the wheel here ? Enums are compile time constants. Just do this :
enum MyEnum
{
FIRST = 4,
OTHER = 10
};
template<MyEnum e>
struct MyTemplate
{
int myArr[e];
};
demo

How to initialize an array in a class whose values can be used in constant-expressions?

I would like to know how to initialize an array in a class whose values can be used in constant-expressions.
Here is an explanation of my problem :
// The goal : initializing an array for a class
// whose values can be used as normal static const
// (as template parameters for example)
class MyClass
{
public:
static const unsigned int value = 42; // <- No problem here
static const unsigned int array[3] = {100, 101, 102}; // <- How to initialize this static const array (with constexpr or metaprogrammation maybe ?)
template<unsigned int T> inline void f() {std::cout<<"Hello, my value is "<<T<<std::endl;} // <- Simple function for demonstration purposes
inline void fvalue() {f<value>();} // <- No problem here
inline void farray() {f<array[1]>();} // <- Big problem here
};
//const unsigned int Class1::array[3] = {100, 101, 102}; // <- If I do this, I will initialize the array but farray() will not compile
Is there any way to do this in C++ 2011 ? (with constexpr or metaprogrammation maybe ?)
Thank you very much !
EDIT : As the title specify it, I need the array to be a member of the class (not a global array).
Yes, you can make it constexpr..
Making it constexpr allows the static member to have more types than just integral or enumeration types, when it is initialized in-class. In particular, the member just needs to be of a literal type, and all expressions in the initializer must be constant expressions. So this is fine
class MyClass
{
public:
static constexpr unsigned int array[3] = {100, 101, 102};
template<unsigned int T> inline void f() {
std::cout<<"Hello, my value is "<<T<<std::endl;
} // <- Simple function for demonstration purposes
inline void farray() {f<array[1]>();}
};
// needs a definition out-of-class too. put it into a .cc file
constexpr unsigned int MyClass::array[3];
Just in case you were wondering what a meta-programming example could look like, here's an example:
#include <iostream>
template<size_t... values>
struct number_list;
template<size_t value, size_t... values>
struct number_list<value, values...>
{
static const size_t val = value;
typedef number_list<values...> next;
};
template<size_t index, typename NumList>
struct indexer
{
static const size_t val = indexer<index - 1, typename NumList::next>::val;
};
template<typename NumList>
struct indexer<0, NumList>
{
static const size_t val = NumList::val;
};
template<typename NumList>
class MyClass
{
public:
template<size_t T> inline void f()
{
std::cout << "Hello, my value is " << T << std::endl;
}
inline void farray() {f<indexer<1, NumList>::val>();}
};
int main()
{
MyClass<number_list<3, 5, 6>> a;
a.farray();
return 0;
}