Extending enum types [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Extending enums in C++?
I am using a library which defines its own set of errors as an enum type.
enum error_type {...}
The library also has a function which takes that enum type, and prints the error.
void set_status(error_type new_error)
If I want to define my own error, and give it to the set_status function, is it possible to extend the error_type enum somehow, or maybe override it?

There might be some sharp edges, but I think this should work for you:
#include<iostream>
// Helper struct
template<typename T, int N, typename... LIST>
struct whereInType {
static const int index = -1;
};
template<typename T, int N, typename HEAD, typename... TAIL>
struct whereInType<T,N,HEAD,TAIL...> {
static const int index = whereInType<T, N+1, TAIL...>::index;
};
template<typename T, int N, typename... TAIL>
struct whereInType<T,N,T,TAIL...> {
static const int index = N;
};
// The actual union type
template<typename... ENUMS>
class enum_union {
public:
template<typename ENUM>
constexpr enum_union(ENUM val) :
which_enum(whereInType<ENUM,0,ENUMS...>::index),
value(val) {}
constexpr operator long long(){
return static_cast<long long>(which_enum)<<32 | value;
}
template<typename ENUM, int IGNORE=0>
constexpr bool operator==(const ENUM& e) {
return *this == enum_union<ENUMS...>(e);
}
template<int IGNORE=0>
constexpr bool operator==(const enum_union<ENUMS...>& oth) {
return which_enum==oth.which_enum && value==oth.value;
}
template<typename T>
constexpr bool operator!=(const T& oth) {
return !(*this == oth);
}
private:
int which_enum;
int value;
};
// An example usage
enum normal_errors {
E_OUTOFMEMORY,
E_IOERROR
};
enum weird_errors {
E_OUTOFAARDVARKS,
E_DIVIDEBYCUCUMBER
};
typedef enum_union<normal_errors, weird_errors> any_error;
// Some tests
void print(any_error e) {
switch(e) {
case any_error(E_OUTOFMEMORY):
std::cout << "Out of Memory\n";
break;
case any_error(E_IOERROR):
std::cout << "I/O Error\n";
break;
case any_error(E_OUTOFAARDVARKS):
std::cout << "WE NEED AARDVARKS!!! NOW!!!!!\n";
break;
case any_error(E_DIVIDEBYCUCUMBER):
std::cout << "please reinstall universe\n";
break;
}
}
main(){
print(E_OUTOFMEMORY);
print(E_IOERROR);
print(E_OUTOFAARDVARKS);
print(E_DIVIDEBYCUCUMBER);
if (any_error(E_OUTOFMEMORY) == E_OUTOFAARDVARKS) {
std::cout<<"bad\n";
}else{
std::cout<<"good\n";
}
if (any_error(E_OUTOFMEMORY) != E_OUTOFAARDVARKS) {
std::cout<<"good\n";
}else{
std::cout<<"bad\n";
}
if (any_error(E_OUTOFMEMORY) == E_OUTOFMEMORY) {
std::cout<<"good\n";
}else{
std::cout<<"bad\n";
}
if (any_error(E_OUTOFMEMORY) != E_OUTOFMEMORY) {
std::cout<<"bad\n";
}else{
std::cout<<"good\n";
}
}

Related

Convert static_assert in if constexpr for type checking to C++14

I am working to downgrade a C++ 17 project to C++ 14. I found the following code:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template <bool flag = false>
void get_assertion_message()
{
static_assert(flag, "unknown type");
}
template <typename T>
const char* get_name()
{
if constexpr (std::is_same<T, int>::value)
{
return "Integer";
}
else if constexpr (std::is_same<T, double>::value)
{
return "Double";
}
else
{
get_assertion_message();
return "Unknown";
}
}
int main()
{
std::cout << get_name<int>() << std::endl;
}
It uses if constexpr to check the type and return the type name accordingly. If no type matches, it calls a template function get_assertion_message which uses static_assert.
I was thinking of applying a solution based on my previous question here: https://stackoverflow.com/a/72300411/4688321. The solution was based on an approach called "tag dispatch".
But, it seems the compilation fails due to static_assert, and doesn't work as expected:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template <bool flag = false>
void get_assertion_message()
{
static_assert(flag, "unknown type");
}
const char* get_name(std::integral_constant<int, 0>)
{
return "Integer";
}
const char* get_name(std::integral_constant<int, 1>)
{
return "Double";
}
const char* get_name(std::integral_constant<int, 2>)
{
get_assertion_message();
return "Unknown";
}
template<int N, class T, class... V>
struct dispatch_constant;
template<int N, class T>
struct dispatch_constant<N, T>
{
static constexpr int value = N;
};
template<int N, typename T, class U, class... V>
struct dispatch_constant<N, T, U, V...>
{
static constexpr int value = std::is_same<T, U>::value ? N - sizeof...(V) - 1 : dispatch_constant<N, T, V...>::value;
};
template <typename T>
const char* get_name()
{
using dispatch_t = std::integral_constant<int, dispatch_constant<2, T, int, double>::value >;
return get_name(dispatch_t{});
}
// template <typename T>
// const char* get_name()
// {
// if constexpr (std::is_same<T, int>::value)
// {
// return "Integer";
// }
// else if constexpr (std::is_same<T, double>::value)
// {
// return "Double";
// }
// else
// {
// get_assertion_message();
// return "Unknown";
// }
// }
int main()
{
std::cout << get_name<int>() << std::endl;
}
I am using GCC 5.4 for compilation in C++ 14. Is it possible to change the above "tag dispatch" solution so that it doesn't fail due to static_assert? Please provide suggestions.
You can split the function template up and make specializations:
template <typename T, bool flag = false>
const char* get_name() {
static_assert(flag, "unknown type");
return nullptr;
}
template <>
const char* get_name<int>() {
return "Integer";
}
template <>
const char* get_name<double>() {
return "Double";
}
Demo

Using enum class values in constexpr branches

the code below prints val2 on both f() calls. What would be a proper way to execute specific branch in f() based on enum value ?
enum class E
{
val1,
val2
};
using val1_t = std::integral_constant<E, E::val1>;
using val2_t = std::integral_constant<E, E::val2>;
template <typename T>
void f(T t)
{
if constexpr (std::is_same_v<T, val1_t>)
{
std::cerr << "val1\n";
}
else
{
std::cerr << "val2\n";
}
}
int main()
{
f(E::val1);
f(E::val2);
}
If you move the enum into the template parameter, then you could use
template <E val>
void f()
{
if constexpr (val == E::val1)
{
std::cerr << "val1\n";
}
else
{
std::cerr << "val2\n";
}
}
And you would use it like
int main()
{
f<E::val1>();
f<E::val2>();
}

boost::variant comparison with contained value

I am trying to find a way to compare boost::variant with underlying value without constructing variant from this underlying value. The question is defined in the comment in "main()" function
And auxiliary question is about the comparison operators defined in the code. How to decrease the # of comparison operators? If boost::variant contains, say, 6 different types, do I have to define 6! operators to be able to compare two variants?
Thanks!
#include <boost/variant.hpp>
namespace test {
namespace Tag {
struct Level1{ int t{ 1 }; };
struct Level2{ int t{ 2 }; };
}
template <typename Kind> struct Node;
using LevelOne = Node<Tag::Level1>;
using LevelTwo = Node<Tag::Level2>;
using VariantNode = boost::variant
<
boost::recursive_wrapper<LevelOne>,
boost::recursive_wrapper<LevelTwo>
>;
typedef VariantNode* pTree;
typedef std::vector<pTree> lstTree;
template <typename Kind> struct Node
{
Node(pTree p, std::string n) : parent(p), name(n) {}
Node(const Node& another) : name(another.name), parent(another.parent) {}
virtual ~Node() {}
std::string name;
pTree parent;
};
bool operator == (const LevelOne& one, const LevelTwo& two) {
return false;
}
bool operator == (const LevelTwo& two, const LevelOne& one) {
return false;
}
bool operator == (const LevelOne& one, const LevelOne& two) {
return true;
}
bool operator == (const LevelTwo& one, const LevelTwo& two) {
return true;
}
}
int main(int argc, char *argv[])
{
using namespace test;
LevelOne l1(nullptr, "level one");
VariantNode tl2 = VariantNode(LevelTwo(nullptr, "level two"));
VariantNode tl1 = VariantNode(LevelOne(nullptr, "level one"));
bool rv = (tl1 == tl2); // this line compiles OK (comparing two variants)
// comparison below does not compile, because "l1" is not a variant.
// Question: How can I compare "variant" value "tl1"
// with one of the possible content values "l1"
bool rv1 = (tl1 == l1);
return 1;
}
The following will work with any number of types in the variant:
template<typename T>
struct equality_visitor : boost::static_visitor<bool> {
explicit constexpr equality_visitor(T const& t) noexcept : t_{ &t } { }
template<typename U, std::enable_if_t<std::is_same<T, U>::value>* = nullptr>
constexpr bool operator ()(U const& u) const {
return *t_ == u;
}
template<typename U, std::enable_if_t<!std::is_same<T, U>::value>* = nullptr>
constexpr bool operator ()(U const&) const {
return false;
}
private:
T const* t_;
};
template<
typename T,
typename... Ts,
typename = std::enable_if_t<
boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
>
>
bool operator ==(T const& t, boost::variant<Ts...> const& v) {
equality_visitor<T> ev{ t };
return v.apply_visitor(ev);
}
template<
typename T,
typename... Ts,
typename = std::enable_if_t<
boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
>
>
bool operator !=(T const& t, boost::variant<Ts...> const& v) {
return !(t == v);
}
The catch is that comparisons must always be of the form value == variant or value != variant rather than variant == value or variant != value. This is because boost::variant<> itself defines these operators to always static_assert, and there is no way for us to make a global operator more specialized than variant<>'s built-in ones.
Online Demo

combining a vector and int in c++11?

Say if I had a vector<string> already defined and filled called test and an int called a. If I wanted to combine these 2 into a single object called combined where i could do combined[0] = test; to initialize/retrieve the object with the vector and combined[1] = a; to initialize/retrieve the object with the int, what would be the best function to do so and how would I do so? I had attempted to do vector<vector<string>, int> but this gave me an error.
Note: I am compiling with -std=c++11 if this matters.
Use a std::tuple<std::vector<std::string>,int>.
#include <tuple>
#include <vector>
#include <string>
int main() {
std::vector<std::string> test;
int a{};
std::tuple<std::vector<std::string>,int> combined;
//To access elements, use `std::get`:
std::get<0>(combined) = test;
std::get<1>(combined) = a;
}
to answer cellsheet's comment: that function already exists, it's called std::make_tuple() (see also comment by fjardon on how to store this).
Btw, why do you need to extend std::vector<std::string> by an int?
If I understand correctly what you're asking, I think you can do this with a std::pair:
std::pair<std::vector<std::string>, int> combined;
combined.first = test; // assign vector
combined.second = a; // assign int
or simply
auto combined = std::make_pair(test,a);
It requires (ugly) type elision:
#include <iostream>
#include <stdexcept>
#include <type_traits>
#include <vector>
class X {
public:
typedef std::vector<std::string> vector_type;
typedef int integer_type;
private:
enum Type {
TypeVector,
TypeInteger
};
template <bool Constant>
class Proxy
{
private:
typedef typename std::conditional<
Constant, const void, void>::type void_t;
public:
typedef typename std::conditional<
Constant, const vector_type, vector_type>::type vector_t;
typedef typename std::conditional<
Constant, const integer_type, integer_type>::type integer_t;
Proxy(vector_t& v)
: m_type(TypeVector), m_data(&v)
{}
Proxy(integer_t& i)
: m_type(TypeInteger), m_data(&i)
{}
operator vector_t& () const {
if(m_type != TypeVector) throw std::runtime_error("Invalid Type");
return *static_cast<vector_t*>(m_data);
}
operator integer_t& () const {
if(m_type != TypeInteger) throw std::runtime_error("Invalid Type");
return *static_cast<integer_t*>(m_data);
}
private:
template <typename T, typename U, bool> struct Assignment
{
static void apply(void_t*, const U&) {}
};
template <typename T, typename U>
struct Assignment<T, U, true>
{
static void apply(void_t* p, const U& value) {
*static_cast<T*>(p) = value;
}
};
template <typename T, typename U>
// Attention: Use a reference - std::is_assignable<int, int>::value> is false;
struct Assign : Assignment<T, U, std::is_assignable<T&, U>::value>
{};
public:
template <typename U>
Proxy&
operator = (const U& value) {
static_assert( ! Constant, "Assignment to Constant");
switch(m_type) {
case TypeVector:
Assign<vector_t, U>::apply(m_data, value);
break;
case TypeInteger:
Assign<integer_t, U>::apply(m_data, value);
break;
default: throw std::out_of_range("Invalid Type");
}
return *this;
}
private:
Type m_type;
void_t* m_data;
};
public:
X() : m_v{"Hello"}, m_i(1) {}
Proxy<true> operator [] (std::size_t i) const {
switch(i) {
case 0: return Proxy<true>(m_v);
case 1: return Proxy<true>(m_i);
default: throw std::out_of_range("Invalid Index");
}
}
Proxy<false> operator [] (std::size_t i) {
switch(i) {
case 0: return Proxy<false>(m_v);
case 1: return Proxy<false>(m_i);
default: throw std::out_of_range("Invalid Index");
}
}
private:
vector_type m_v;
integer_type m_i;
};
int main() {
// Note: The Proxy has no operator []
// const
{
const X x;
const X::vector_type& v = x[0];
std::cout << v[0] << " " << x[1] << std::endl;
}
// non const
{
X x;
X::vector_type& v = x[0];
v[0] = "World";
x[1] = 2;
std::cout << v[0] << " " << x[1] << std::endl;
}
}
You might consider boost::any, instead.

Template specialization for char pointer?

boost::lexical_cast is a great tool but in my application I ran into a limitation in string -> bool conversion that is bugging me. I need to convert all strings like "0", "false" and "FALSE" into false and "1", "true" and "TRUE" into true.
boost::lexical_cast only support conversion from/to "0" and "1". So my idea was to write my own conversion function which seems to work fine:
bool str_to_bool(const std::string &str)
{
if(str == "1" || str == "true" || str == "TRUE")
return true;
else if(str == "0" || str == "false" || str == "FALSE")
return false;
else
throw std::runtime_error("Bad cast from std::string to bool!");
}
Now I wan to write a wrapper round boost::lexical_cast and write my own template specializations for it. Here is what I've got so far:
template<typename Target, typename Source>
inline Target my_cast(const Source& src)
{
return boost::lexical_cast<Target>(src);
}
template<>
inline bool my_cast(const std::string& src)
{
return str_to_bool(src);
}
This works great for integers or std::string but obviously fails for string literals or character pointers:
int main(int argc, char* argv[])
{
std::cout << my_cast<bool>(1) << std::endl; //OK
std::cout << my_cast<bool>(std::string("true")) << std::endl; //OK
std::cout << my_cast<bool>("true") << std::endl; //Fail!
return 0;
}
So I tried to write another specialization for char * but it fails to compile!
//does not compile!
template<>
inline bool my_cast(const char*& src)
{
return str_to_bool(src);
}
What is the correct way to support both std::string and char *?
EDIT 1: the title was stupid. Fixed it.
EDIT 2: I borrowed a solution from boost itself. Posted as a new answer.
If you say this:
template<>
inline bool my_cast<bool, std::string>(std::string const & src)
{
return str_to_bool(src);
}
template<>
inline bool my_cast<bool, const char *>(const char * const & src)
{
return str_to_bool(src);
}
Then at least you can make the following work:
int main(int argc, char* argv[])
{
const char * const q = "true";
std::cout << my_cast<bool>(q) << std::endl; //Fail!
return 0;
}
Update: Voila:
typedef char FT[5];
template<>
inline bool my_cast<bool, FT>(const FT & src)
{
return str_to_bool(src);
}
Here is a solution that works. I got the idea from boost::lexical_cast itself:
template<class T>
struct array_to_pointer_decay
{
typedef T type;
};
template<class T, std::size_t N>
struct array_to_pointer_decay<T[N]>
{
typedef const T * type;
};
template<typename Target, typename Source>
Target my_cast_internal(const Source& s)
{
return boost::lexical_cast<Target>(s);
}
template<>
inline bool my_cast_internal(const std::string& src)
{
return str_to_bool(src);
}
template<>
inline bool my_cast_internal(const char* const& src)
{
return str_to_bool(src);
}
template<typename Target, typename Source>
inline Target my_cast(const Source& s)
{
typedef typename array_to_pointer_decay<Source>::type src;
return my_cast_internal<Target, src>(s);
}
The main challenge is to deal with array types. The array_to_pointer_decay converts any array type to the corresponding pointer type. The rest is easy now.
You need to take a const char*, not a const char*&. The mutable lvalue reference here will only bind to an lvalue, whereas the decay from the array type that the string literal actually is will only produce an rvalue const char*, to which you can only bind a const reference.
Let me add this as a new answer... a type-erasing version!
For C++98/03
/* Core caster */
bool str_to_bool(const std::string &str)
{
if(str == "1" || str == "true" || str == "TRUE")
return true;
else if(str == "0" || str == "false" || str == "FALSE")
return false;
else
throw std::runtime_error("Bad cast from std::string to bool!");
}
/* Type erasing scaffold */
struct TypeEraseBase
{
virtual bool cast() const = 0;
virtual ~TypeEraseBase() { }
};
template <typename T>
struct TypeEraseImpl : public TypeEraseBase
{
TypeEraseImpl(const T & tt) : t(tt) { }
virtual bool cast() const { return boost::lexical_cast<T>(t); }
private:
const T & t;
};
/* Specializations go here */
template <>
struct TypeEraseImpl<std::string> : public TypeEraseBase
{
TypeEraseImpl(const std::string & tt) : t(tt) { }
virtual bool cast() const { return str_to_bool(t); }
private:
const std::string & t;
};
template <size_t N>
struct TypeEraseImpl<char[N]> : public TypeEraseBase
{
TypeEraseImpl(const char (& tt)[N]) : t(tt) { }
virtual bool cast() const { return str_to_bool(std::string(t)); }
private:
const char (& t)[N];
};
template <>
struct TypeEraseImpl<const char *> : public TypeEraseBase
{
TypeEraseImpl(const char * const & tt) : t(tt) { }
virtual bool cast() const { return str_to_bool(std::string(t)); }
private:
const char * const & t;
};
/* User interface class */
struct my_cast
{
template <typename T> my_cast(const T & tt)
: pt(new TypeEraseImpl<T>(tt))
{
}
~my_cast() { if (pt) delete pt; }
inline bool cast() const { return pt->cast(); }
private:
const TypeEraseBase * const pt;
};
// Usage example
int main()
{
const char * const q = "true";
std::cout << my_cast(1).cast() << std::endl;
std::cout << my_cast(std::string("true")).cast() << std::endl;
std::cout << my_cast("true").cast() << std::endl;
std::cout << my_cast(q).cast() << std::endl;
return 0;
}
Type-traited version, templated return type
#include <string>
#include <stdexcept>
#include <iostream>
#include <ostream>
#include <boost/lexical_cast.hpp>
template <typename T> struct is_string : std::false_type { };
template <> struct is_string<std::string> : std::true_type { };
template <> struct is_string<const char *> : std::true_type { };
template <std::size_t N> struct is_string<char[N]> : std::true_type { };
/* The actual caster class */
template <typename T, bool B> struct to_bool
{
static inline bool cast(const T & t)
{
return boost::lexical_cast<T>(t);
}
};
template <typename T> struct to_bool<T, true>
{
static inline bool cast(const T & t)
{
const std::string str(t);
if(str == "1" || str == "true" || str == "TRUE")
return true;
else if(str == "0" || str == "false" || str == "FALSE")
return false;
else
throw std::runtime_error("Bad cast from std::string to bool!");
}
};
/* Type erasing helper class */
template <typename Target>
struct TypeEraseBase
{
virtual Target cast() const = 0;
virtual ~TypeEraseBase() { }
};
template <typename T, typename Target>
struct TypeEraseImpl : public TypeEraseBase<Target>
{
TypeEraseImpl(const T & tt) : t(tt) { }
virtual Target cast() const { return boost::lexical_cast<T>(t); }
private:
const T & t;
};
template <typename T>
struct TypeEraseImpl<T, bool> : public TypeEraseBase<bool>
{
TypeEraseImpl(const T & tt) : t(tt) { }
virtual bool cast() const { return to_bool<T, is_string<T>::value>::cast(t); }
private:
const T & t;
};
/* User interface class */
template <typename Target>
struct my_cast
{
template <typename T> my_cast(const T & tt)
: pt(new TypeEraseImpl<T, Target>(tt)) { }
~my_cast() { if (pt) delete pt; }
inline Target cast() const { return pt->cast(); }
private:
const TypeEraseBase<Target> * const pt;
};
template <typename Target>
std::ostream & operator<<(std::ostream & stream, const my_cast<Target> & c)
{ return stream << c.cast(); }
/* Usage */
int main()
{
const char * const q = "true";
std::cout << my_cast<bool>(1) << std::endl;
std::cout << my_cast<bool>(std::string("true")) << std::endl;
std::cout << my_cast<bool>("true") << std::endl;
std::cout << my_cast<bool>(q) << std::endl;
return 0;
}