I have an Expression class that stores algebraic terms. The public interface I want it to have is something like:
expr.add({1}) // add term "x1". (error: code adds constant 1)
expr.add({0,1}) // add term "x0 * x1".
expr.add({0},2) // add term "2 * x0"
expr.add(2) // add constant 2
But I'm having the problem that expr.add({1}) is being interpreted as adding the integer 1, not adding the vector containing 1. Is there any way I can fix the implementation below to allow for the interface above? (Or at the very least catch it?) Because typing out expr.add(std::vector({1})) is far too verbose.
#include <tuple>
#include <vector>
#include <unordered_set>
#include <iostream>
class Expression
{
using var_t = unsigned int;
using term_t = std::pair<int, std::vector<var_t>>;
std::vector<term_t> terms;
public:
void add(const std::vector<var_t>& vars, int coeff=1)
{
std::cout << "Adding a term" << std::endl;
terms.push_back(std::make_pair(coeff, vars));
}
void add(int constant)
{
std::cout << "Adding a constant" << std::endl;
terms.push_back(std::make_pair(constant, std::vector<var_t>{}));
}
};
int main()
{
Expression expr;
expr.add({1},1); // "Adding a term"
expr.add({1}); // "Adding a constant"
expr.add(1); // "Adding a constant"
}
You can add an overload for initializer_list which will bind to the argument if it's in a brace initializer
void add(std::initializer_list<var_t> vars, int coeff=1)
{
add(std::vector<var_t>(vars), coeff);
}
In the implementation, you can just call the vector overload explicitly and/or give the user a warning.
Here's a demo.
You can change the parameter type to std::initializer_list, which would be preferred.
void add(std::initializer_list<var_t> vars, int coeff=1)
{
std::cout << "Adding a term" << std::endl;
terms.push_back(std::make_pair(coeff, std::vector<var_t>(vars)));
}
LIVE
You may change it to initializer_list in the arguments.
void add(std::initializer_list<var_t> vars, int coeff=1)
Related
I am trying to create a map with string as key and a generic method as value in C++, but I do not know if that is even possible. I would like to do something like that:
void foo(int x, int y)
{
//do something
}
void bar(std::string x, int y, int z)
{
//do something
}
void main()
{
std::map<std::string, "Any Method"> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello", 1, 2);
}
Is that possible? If yes, how can I realise this?
You can type-erase the function types into a container, then provide a template operator(). This will throw std::bad_any_cast if you get it wrong.
N.B. because of the type erasure, you will have to specify exactly matching arguments at the call site, as e.g. std::function<void(std::string)> is distinct from std::function<void(const char *)>, even though both can be called with a value like "Hello".
#include <any>
#include <functional>
#include <map>
#include <string>
#include <iostream>
template<typename Ret>
struct AnyCallable
{
AnyCallable() {}
template<typename F>
AnyCallable(F&& fun) : AnyCallable(std::function(std::forward<F>(fun))) {}
template<typename ... Args>
AnyCallable(std::function<Ret(Args...)> fun) : m_any(fun) {}
template<typename ... Args>
Ret operator()(Args&& ... args)
{
return std::invoke(std::any_cast<std::function<Ret(Args...)>>(m_any), std::forward<Args>(args)...);
}
std::any m_any;
};
void foo(int x, int y)
{
std::cout << "foo" << x << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar" << x << y << z << std::endl;
}
using namespace std::literals;
int main()
{
std::map<std::string, AnyCallable<void>> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello, std::string literal"s, 1, 2);
try {
map["bar"]("Hello, const char *literal", 1, 2); // bad_any_cast
} catch (std::bad_any_cast&) {
std::cout << "mismatched argument types" << std::endl;
}
map["bar"].operator()<std::string, int, int>("Hello, const char *literal", 1, 2); // explicit template parameters
return 0;
}
The most (I cannot say best here) you can do is to use a signature erasure. That mean to convert the pointer to functions to a common signature type, and then convert them back to the correct signature before using them.
That can only be done in very special use cases (I cannot imagine a real world one) and will be highly unsecure: nothing prevent you to pass the wrong parameters to a function. In short: NEVER DO THIS IN REAL WORLD CODE.
That being said, here is a working example:
#include <iostream>
#include <string>
#include <map>
typedef void (*voidfunc)();
void foo(int x, int y)
{
std::cout << "foo " << x << " " << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar " << x << " " << y << " " << z << std::endl;
}
int main()
{
std::map<std::string, voidfunc> m;
m["foo"] = (voidfunc) &foo;
m["bar"] = (voidfunc)& bar;
((void(*)(int, int)) m["foo"])(1, 2);
((void(*)(std::string, int, int)) m["bar"])("baz", 1, 2);
return 0;
}
It gives as expected:
foo 1 2
bar baz 1 2
I could not find in standard whether this invokes or not Undefined Behaviour because little is said about function pointer conversions, but I am pretty sure that all common compilers accept that, because it only involve function pointers casting.
You cannot store functions with different signatures in a container like map, no matter if you store them as a function pointer or std ::function<WHATEVER>. The information about the signature of the function is one and only one in both cases.
The types for the value in map is one, meaning that the object stored in it are all of the same type.
So if your functions have all the same signature, then it's easy, otherwise, you have to abandon type safety and start walking in a very dangerous realm.
The one in which you erase the type information about the functions stored inside the map.
This translates to something like map<string, void*>.
I am not sure I understand why the first test evaluates to true and the second to false. I know that the information from typeid().name() is usually not reliable, but my main problem is with the typeid itself. I don't understand why the type of *test is not Location<1>, or what else is wrong. Any thoughts? Is there same wrapper around a type here that I don't see? Thanks in advance, and apologies if the answer is obvious.
#include <iostream>
#include <utility>
#include <typeinfo>
class LocationAbstract
{
virtual void get_() = 0;
};
template<int i>
class Location : public LocationAbstract
{
public:
static constexpr int test = i;
virtual void get_() override
{
return;
}
};
template <int i>
Location<i> LocationGenerator()
{
Location<i> test{};
return test;
}
int main()
{
LocationAbstract *table[10];
table[0] = new decltype(LocationGenerator<0>());
table[1] = new decltype(LocationGenerator<1>());
Location<1> *test;
try
{
std::cout << "Casting\n";
test = dynamic_cast<Location<1>*>(table[1]);
}
catch (std::bad_cast &e)
{
std::cout << "Bad cast\n";
}
// test1, evaluates to true
std::cout << (typeid(*test) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid(*test).name() << "\n";
std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n----\n";
// test2, why does this evaluate to false while the above evaluates to true ?
std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";
std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n";
auto test1 = Location<1>();
auto test2 = *dynamic_cast<Location<1>*>(table[1]);
std::cout << typeid(test1).name() << " and " << typeid(test2).name() << "\n";
return 0;
}
An extra set of () makes all the difference here. In typeid(Location<1>()) and typeid((Location<1>())), Location<1>() actually means two totally different things.
In typeid(Location<1>()), Location<1>() is interpreted as a function type that returns a Location<1> and takes no parameters.
In typeid((Location<1>())), Location<1>() is interpreted as value-initializing an anonymous Location<1> object.
The typeid operator can work on either types or expressions. That is, you can say typeid(int) as well as typeid(42). Since Location<1>() can be interpreted as a type, the language does so. (Location<1>()) cannot be interpreted as a type though, so it must be interpreted as an expression. The only thing Location<1>() can mean as part of an expression is to value-initialize an anonymous Location<1> object, so typeid gives you the type of that object.
Let this be yet another reason to prefer uniform-initialization syntax when creating temporary objects; Location<1>{} would not have this ambiguity.
Examine these two lines:
std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";
In the first line, you use typeid(Location<1>()). typeid can take types as well as expressions, and Location<1>() is a function type with no parameters and a return type of Location<1>.
So why does the name print the same? That's because of the second line: typeid((Location<1>())). By wrapping the argument in parentheses, it is no longer a valid type, so it is treated as an expression and the name of typeid(Location<1>) is printed. Removing the extra parentheses prints F8LocationILi1EEvE under the same mangling scheme.
To avoid the ambiguity, you can also use the type directly (typeid(Location<1>)) or use braces: typeid(Location<1>{})).
Introduction
Hello everyone, i try to use boost::unordered_set for a custom class type. The class stores information about coordinates and several other values but only the coordinates are used to create the hash value. Now if i want to insert a point and there is already a point with equal coordinates (hence a set) i need to change a third value from the original object (like object.isDuplicate = true very simplified). Please do not stick too much to the bool value and duplicate detection cause in the original code it is a bit more complex but it should only show that i need a non-const access to the stored class. I can only use boost 1.53 and C++03 and GCC 4.4.3
The problem
The problem is now when i try to insert a point with boost::unordered_set::insert i get a pair<iterator, bool> of which the first member is an immutable iterator to the inserted or original entry and the second is a bool indicating if the value was inserted or not. I can not change the value with an immutable iterator unfortunately so i had to think of something different. So i now try to store a pointer to my object in the set and then access it via this pointer to change the value (which should be okay since the value has nothing to do with the hash value and thus does not alter the key). So i tried to overload the boost::hash_value function to accept a pointer to my class like this:
size_t hash_value(const A * a) {
size_t seed = 0;
boost::hash_combine(seed, a->a);
boost::hash_combine(seed, a->b);
return seed;
}
But the unordered_set does not seem to use my overloaded function (i tried printing the seed at the end but it does not show up hence i assume it uses a different overload) even if i initialize my set with unordered_set< A *, boost::hash<A *> >. For the hashing aspect: when i try to use the set without a pointer it works fine but i can not alter the value.
Possible problem
I searched a bit around in the boost::hash reference and found this overload template<typename T> std::size_t hash_value(T* const&); which i think is used instead of my own one (and simply hashes with the objects address) but then i wonder why my compiler does not prompt a redefinition of this function (i compile with -Wall -Wextra -pedantic flags enabled.
Question
So is this the actual problem? And if it is how can i tell my compiler to explicitely use my custom hash function?
Code
At last a little example i wrote to test everything
#include <iostream>
#include <string>
#include <boost/functional/hash.hpp>
#include <boost/unordered_set.hpp>
using boost::unordered_set;
struct A {
double a;
double b;
bool isDup;
A(const double a, const double b): a(a), b(b), isDup(false) {}
A(const A & a): a(a.a), b(a.b), isDup(a.isDup) {}
/* Two equal As ought to have a bitwise equal floating point value so this is okay */
bool operator==(const A & a) const {
if (a.a != this->a) return false;
if (a.b != this->b) return false;
return true;
}
};
size_t hash_value(const A * a) {
size_t seed = 0;
boost::hash_combine(seed, a->a);
boost::hash_combine(seed, a->b);
std::cout << "Seed: " << seed << std::endl; /* This is not printed so i assume the function is not called */
return seed;
}
int main() {
A a1(1.2, 2.3);
A a2(2.3, 3.4);
A a3(3.4, 4.5);
A a4(a1);
unordered_set< A *, boost::hash<A *> > usa; /* This was unintended lol */
if ( ! usa.insert(&a1).second ) std::cout << "Error " << a1.a << ", " << a1.b << " is already in set" << std::endl;
if ( ! usa.insert(&a2).second ) std::cout << "Error " << a2.a << ", " << a2.b << " is already in set" << std::endl;
if ( ! usa.insert(&a3).second ) std::cout << "Error " << a3.a << ", " << a3.b << " is already in set" << std::endl;
if ( ! usa.insert(&a4).second ) {
/* This is not called */
std::cout << "Error " << a4.a << ", " << a4.b << " is already in set" << std::endl;
(*(usa.insert(&a4).first))->isDup = true;
}
}
There are a couple of issues with your original function hash_value:
It must be inside boost namespace because boost::hash<T*> invokes boost::hash_value which disables argument-dependent name lookup.
In templates name lookup is performed twice: at declaration and instantiation time. At instantiation time only argument-dependent name lookup is performed but it is disabled by 1. This is why your hash function must be declared before the definition of boost::hash (before including boost/hash.hpp).
E.g.:
#include <cstddef> // std::size_t
struct A;
namespace boost { inline std::size_t hash_value(A* a); }
#include <iostream>
#include <string>
#include <boost/functional/hash.hpp>
#include <boost/unordered_set.hpp>
struct A { /*... */};
size_t boost::hash_value(A* a) {
size_t seed = 0;
boost::hash_combine(seed, a->a);
boost::hash_combine(seed, a->b);
std::cout << "Seed: " << seed << std::endl; /* This is not printed so i assume the function is not called */
return seed;
}
Also, you need to specify your own element comparison class, the default one in boost::unordered_set compares pointers.
As a side note the design of boost::hash and std::hash is less than ideal in respect of combining hashes of multiple members. I cannot recommend enough using the new hash framework from N3980 Types Don't Know #.
Okay i found a solution (or a workaround rather?) by myself now. A second problem was the equal_to class which is used by default by boost::unordered_set. equal_to<A *> would never return false because we always have distinct points and thus &a1 == &a2 would always evaluate to false so i had to write my own comparator as well which dereferences the objects before comparing them and then invoces their operator==.
Then I simply encapsulated the hash function and the comparator in a separate class and then pass them as template arguments when creating the set like this:
class compA {
public:
size_t operator()(const A * a) const {
size_t seed = 0;
boost::hash_combine(seed, a->a);
boost::hash_combine(seed, a->b);
return seed;
}
bool operator()(const A * a1, const A * a2) const {
if (*a1 == *a2) return true;
return false;
}
};
unordered_set<A *, compA, compA> usa;
But i still would like to know why my initial attempt did not work.
I am trying to get a std::bad_variant_access exception when the variant is not in the list .But the below code doesn't work it returns a implicit converted ASCII int value
what changes should I do that variant is strict on type selection
#include <iostream>
#include <variant>
using namespace std;
struct printer
{
void operator()(int x) {
cout << x << "i"<<endl;
}
void operator()(float x) {
cout << x << "f"<<endl;
}
void operator()(double x)
{
cout << x << "d" << endl;;
}
};
int main() {
using my_variant = std::variant<int, float, double>;
my_variant v0('c');
try {
std::visit(printer{}, v0);
}
catch(const std::bad_variant_access& e) {
std::cout << e.what() << '\n';
}
return 0;
}
Output:
99i
Whereas I was expecting to get std::bad_variant_access exception
Code
std::visit will only trigger a bad_variant_access exception if the variant is valueless_by_exception (C++17, see N4659 23.7.3.5 [variant.status] )
What this means is that if you tried to set a variant value in a fashion that throws an exception, the variant is left in a "valueless" state, so visitation is not permitted.
To trigger it, we can change the code like so:
struct S{
operator int() const{throw 42;}
};
struct printer{//as before};
int main() {
using my_variant = std::variant<int, float, double>;
my_variant v0{'c'};
try{
v0.emplace<0>(S());
}catch(...){}
try {
std::visit(printer{}, v0);
}
catch(const std::bad_variant_access& e) {
std::cout << e.what() << '\n';
}
}
Demo
Frank already answered why you could construct your variant in the first place using a char (construction chosen via overload).
You can not trigger a bad_variant_access by attempting to first construct a variant in a fashion that will throw because [variant.ctor] dictates that the constructor will rethrow that exception (in this case int).
According to the documentation for std::variant:
That constructor of variant does the following:
Constructs a variant holding the alternative type T_j that would be selected by overload resolution for the expression F(std::forward(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types... in scope at the same time. [...]
I.e. std::variant will get the first type that is constructible from the passed argument. In this case, int is constructible from a char, so the variant gets assigned as such.
I am trying to create a map with string as key and a generic method as value in C++, but I do not know if that is even possible. I would like to do something like that:
void foo(int x, int y)
{
//do something
}
void bar(std::string x, int y, int z)
{
//do something
}
void main()
{
std::map<std::string, "Any Method"> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello", 1, 2);
}
Is that possible? If yes, how can I realise this?
You can type-erase the function types into a container, then provide a template operator(). This will throw std::bad_any_cast if you get it wrong.
N.B. because of the type erasure, you will have to specify exactly matching arguments at the call site, as e.g. std::function<void(std::string)> is distinct from std::function<void(const char *)>, even though both can be called with a value like "Hello".
#include <any>
#include <functional>
#include <map>
#include <string>
#include <iostream>
template<typename Ret>
struct AnyCallable
{
AnyCallable() {}
template<typename F>
AnyCallable(F&& fun) : AnyCallable(std::function(std::forward<F>(fun))) {}
template<typename ... Args>
AnyCallable(std::function<Ret(Args...)> fun) : m_any(fun) {}
template<typename ... Args>
Ret operator()(Args&& ... args)
{
return std::invoke(std::any_cast<std::function<Ret(Args...)>>(m_any), std::forward<Args>(args)...);
}
std::any m_any;
};
void foo(int x, int y)
{
std::cout << "foo" << x << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar" << x << y << z << std::endl;
}
using namespace std::literals;
int main()
{
std::map<std::string, AnyCallable<void>> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello, std::string literal"s, 1, 2);
try {
map["bar"]("Hello, const char *literal", 1, 2); // bad_any_cast
} catch (std::bad_any_cast&) {
std::cout << "mismatched argument types" << std::endl;
}
map["bar"].operator()<std::string, int, int>("Hello, const char *literal", 1, 2); // explicit template parameters
return 0;
}
The most (I cannot say best here) you can do is to use a signature erasure. That mean to convert the pointer to functions to a common signature type, and then convert them back to the correct signature before using them.
That can only be done in very special use cases (I cannot imagine a real world one) and will be highly unsecure: nothing prevent you to pass the wrong parameters to a function. In short: NEVER DO THIS IN REAL WORLD CODE.
That being said, here is a working example:
#include <iostream>
#include <string>
#include <map>
typedef void (*voidfunc)();
void foo(int x, int y)
{
std::cout << "foo " << x << " " << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar " << x << " " << y << " " << z << std::endl;
}
int main()
{
std::map<std::string, voidfunc> m;
m["foo"] = (voidfunc) &foo;
m["bar"] = (voidfunc)& bar;
((void(*)(int, int)) m["foo"])(1, 2);
((void(*)(std::string, int, int)) m["bar"])("baz", 1, 2);
return 0;
}
It gives as expected:
foo 1 2
bar baz 1 2
I could not find in standard whether this invokes or not Undefined Behaviour because little is said about function pointer conversions, but I am pretty sure that all common compilers accept that, because it only involve function pointers casting.
You cannot store functions with different signatures in a container like map, no matter if you store them as a function pointer or std ::function<WHATEVER>. The information about the signature of the function is one and only one in both cases.
The types for the value in map is one, meaning that the object stored in it are all of the same type.
So if your functions have all the same signature, then it's easy, otherwise, you have to abandon type safety and start walking in a very dangerous realm.
The one in which you erase the type information about the functions stored inside the map.
This translates to something like map<string, void*>.