std::transform with variant - c++

I have two vectors: A vector of a type that acts as a union, whose type I can retrieve.
The other vector is a vector of variants of another type.
I want to use std::transform to do a conversion to one of my variant types.
However, I receive a compile error that std::transform or rather the lambda can not deduce the return type.
Here is an example:
#include <variant>
#include <vector>
#include <algorithm>
#include <stdexcept>
// third party types
struct fooData {};
struct barData {};
struct baz {
int foo_or_bar;
fooData f;
barData b;
fooData* asFoo() {
return &f;
}
barData* asBar() {
return &b;
}
};
//my types
struct bar {
};
struct foo {
};
//converter
struct converter {
bar operator()(const barData& b) {
return bar{};
}
foo operator()(const fooData& f) {
return foo{};
}
};
int main() {
using entry = std::variant<bar,foo>;
//vector of third party type
std::vector<baz> bazzs{};
//vector of my variant type
std::vector<entry> target{};
std::transform(bazzs.begin(),bazzs.end(),std::back_inserter(target), [](baz& bazzer){
//both foo and bar are part of the variant, but it refuses to compile
switch(bazzer.foo_or_bar) {
case 0:
return converter{}(*(bazzer.asBar()));
case 1:
return converter{}(*(bazzer.asFoo()));
default:
throw std::runtime_error("ERROR");
}
});
}
How can I make this work?

Add a trailing return type specifier to your lambda:
// vvvvvvvv -- Add This
[](baz& bazzer) -> entry {
// ...
}
A lambda, like any function, has to return one single type. As it currently stands it returns different types though depending on which case gets chosen: either bar in case 0 or foo in case 1. Since not all code paths return the same type, the compiler can't decide which type the lambda should return unless you tell it.

Related

Hiding the argument type of std::function

I have two objects, Higher and Lower. I don't want Lower to know about Higher.
My goal is to pass a function to object Lower that takes a pointer to a Higher and I don't want to reveal that type to Lower. My idea is to cast Higher* to void*.
Here's my non-functional attempt at implementing this:
#include <functional>
using namespace std;
struct Higher {
int val;
};
void foo(Higher* context) {
int val = context->val;
}
struct Lower {
std::function<void(void*)> m_function;
Lower(std::function<void(void*)> function) : m_function(function) {}
};
int main()
{
Higher context;
std::function<void(void*)> foo_void = [foo] (void* context) {
foo(static_cast<Higher*>(context));
};
Lower lower(foo_void);
lower.m_function(static_cast<void*>(&context));
return 0;
}
EDIT:
Here's a template implementation as suggested by Silvio Mayolo that doesn't quite work because the real code is a little different from the simplified example I've provided in the OP. I can't change the signature of bar() or make it a member method of Lower.
#include <functional>
#include <utility>
using namespace std;
struct Higher {
int val;
};
void foo(Higher* context) {
int val = context->val;
}
// ---------------------------------
void bar(void* context) {
// A problem, can't access T here
auto big_context = static_cast<std::pair<Lower*, T*>*>(context);
big_context->first->m_function(big_context->second);
}
template<typename T>
struct Lower {
std::function<void(T*)> m_function;
T* m_context;
Lower(std::function<void(T*)> function, T* context)
: m_function(function)
, m_context(context)
{
std::pair<Lower*, T*> big_context = {this, m_context};
bar(static_cast<void*>(&big_context));
}
};
int main()
{
Higher context;
Lower<Higher> lower(foo, &context);
return 0;
}
How would you actually implement it?
The only error in your initial sample was capture of non-variable 'foo'. If you remove the foo capture, it is functional.
In the second sample, the argument is available at the time the function is constructed (you chose to pass them both in the constructor), so you can instead just bind the argument immediately and save a std::function<void()>. See here.
Because the signature of the function taking a single void* is something you cannot change, according to the question and that has to hide something invocable, the most flexible option is to pass a pointer to a std::function<void()>.

How would I use type as a "variable"?

#include <iostream>
#include <string>
#include <vector>
#include <map>
std::vector<std::pair<std::string, [type of the object, entity or banana]>> nep; //[type of the object, entity or banana] is my imaginary type
class Entity
{
private:
int x;
public:
Entity(const int x) : x(x) {};
int GetX() const { return x; };
};
class Banana
{
private:
int y;
public:
Banana(const int y) : y(y) {};
int GetY() const { return y; };
};
[type of the object, entity or banana] CreateObj(std::string name) //Used that imaginary variable here again
{
for (unsigned short int i = 0; i < nep.size(); i++)
{
if (nep.at(i).first == name)
{
return [new object with type = nep.at(i).second];
}
}
}
int main()
{
nep.push_back({ "ent", Entity });
nep.push_back({ "banan", Banana });
CreateObj(banan).GetY();
std::cin.get();
}
[type of the object, entity or banana] is my imaginary variable-type thing.
What I'd like to do is pass there a class for example, and then using CreateObj() function I'd like to create new object of that type and use it.
How can I do that?
Short answer: no
Long answer:
You have tools like std::type_index and typeid, but they won't do what you want.
You can however store factory function instead of a type:
using result = std::any; // or some other common type
std::map<std::string, std::function<std::any()>> nep;
nep["banana"] = []{ return Banana{}; };
nep["entity"] = []{ return Entity{}; };
// Call the functions:
result my_banana = nep["banana"]();
Banana& b = std::any_cast<Banana&>(my_banana);
The functions stored in the map create instances of a known type. Since the map has to store functions of the same type, it must be returned through a common type. That common type can be std::any, std::variant<Banana, Entity> or a pointer to a base class.
Then you can search the map for a factory function and call it to get the created object. It must be unwrapped correctly to access the variable through the right type to access members.
If you do not want to use polymorphism, you can do something with meta-programming:
enum class ClassType {
EntityType,
BananaType,
};
namespace internal {
template <ClassType Type>
struct _build_type {};
template <>
struct _build_type<ClassType::EntityType> {
constexpr auto operator()() {
return EntityType();
}
};
template <>
struct _build_type<ClassType::BananaType> {
constexpr auto operator()() {
return BananaType();
}
};
}
And then, your construct object:
template <ClassType Type>
constexpr auto create_instance() {
return internal::_build_type<Type>{}();
}
So you can do:
const auto object = create_instance<BananaType>();
This thing will increase your compilation time but it does not have any performance penalty during runtime.

Map from int to type specifier

I want to use a map to refer to a type specifier mainly to shorten my code from multiple uses of
std::unique_ptr< Class >(new class1);
to
std::unique_ptr< Class >(new sampleMap[enum1]);
and then define my map so that it refers each enum value (enum1, enum2, ...) to my classes (class1, class2, ...).
But I cannot define my map with the values being a type name like this
std::map < int, Class > mapName {
{0, class1},
{0, class1},
...
};
since type name is not allowed in maps.
The main reason I'm looking for an answer for this is to make my code more succinct by replacing a series of "if/else if" statements or "switch-case" statements into only one line of code where the output std::unique_ptr<Class>(new class1); is dynamically figured out through the map that I define. So, I just input the enum number and get the corresponding class instantiated for me. Otherwise, I would have to do this:
if (enum1 = 0)
{
std::unique_ptr< Class >(new class1);
}
else if (enum2 = 0)
{
std::unique_ptr< Class >(new class2);
}
(or a switch-case)
But I want to do all above in one line like this:
std::unique_ptr<Class>(new sampleMap[enum1]);
plus the map declaration.
Any clue how this could be done?
You cannot easily implement an std::map that will return types as values the way you are trying to do it. You would need to implement your own class that would represent types as values. However, since your goal seems to be to create instances of objects where the concrete type depends on a value, an easily solution is to make a map of functions instead. This assumes that all the types you want to support derive from a common type. Each value can hold a function which constructs the correct object. If your types do not derive from a common type, then you will need to preform further type erasure (perhaps with std::any).
#include <functional>
#include <iostream>
#include <map>
#include <memory>
// Simple set of classes
// Class is the base type
// Class1 and Class2 derive from Class
struct Class { virtual void func() = 0; };
struct Class1 : Class {
void func() override { std::cout << "Class1\n"; }
};
struct Class2 : Class {
void func() override { std::cout << "Class2\n"; }
};
// A map of factory functions
const std::map<int, std::function<std::unique_ptr<Class>()>> mapName = {
{ 1, []() {return std::make_unique<Class1>(); } },
{ 2, []() {return std::make_unique<Class2>(); } }
};
int main()
{
auto foo = mapName.at(2)(); // Make an object of type associated with the value 2
foo->func(); // Prints "Class2\n"
return 0;
}
Depending on where you want to use this code, you might want to do this with an if-else chain. std::functions are usually very difficult for the compiler to optimize, so if you expect this code to be called frequently enough, it's probably more efficient to just code it out:
(using #FrançoisAndrieux's example)
#include <iostream>
#include <memory>
#include <stdexcept>
// Simple set of classes
// Class is the base type
// Class1 and Class2 derive from Class
struct Class {
virtual void func() = 0;
};
struct Class1 : Class {
void func() override { std::cout << "Class1\n"; }
};
struct Class2 : Class {
void func() override { std::cout << "Class2\n"; }
};
std::unique_ptr<Class> make_class(int i)
{
if (i == 0) return std::make_unique<Class1>();
else if (i == 1) return std::make_unique<Class2>();
throw std::out_of_range{ "Asked to construct an unknown type" };
}
int main()
{
auto foo = make_class(1); // Make an object of type associated with the value 1
foo->func(); // Prints "Class2\n"
return 0;
}
If the number of values is large, you might gain by doing a binary search (or just a switch):
// If there are 128 elements, for example
if (!(0 <= i && i < 128)) throw std::out_of_range{ "..." };
if (i < 64) {
if (i < 32) {
...
} else {
...
}
} else {
...
}
It's messy but it's only in one place.
To make a more optimizable version, you can do some minimal metaprogramming / expression templates:
#include <iostream>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>
// Simple set of classes
// Class is the base type
// Class1 and Class2 derive from Class
struct Class {
virtual void func() = 0;
};
struct Class1 : Class {
void func() override { std::cout << "Class1\n"; }
};
struct Class2 : Class {
void func() override { std::cout << "Class2\n"; }
};
template<typename R, typename SwBase, typename T, typename F>
struct Switch
{
SwBase base;
T value;
F fn;
constexpr Switch(SwBase base, T value, F fn)
: base{ std::move(base) }
, value{ std::move(value) }
, fn{ std::move(fn) }
{}
constexpr R operator()(T val) const {
if (value == val) return fn();
return base(val);
}
};
template<typename R, typename SwBase, typename T, typename F>
constexpr auto make_switch_impl(SwBase&& swb, T&& t, F&& f)
{
return Switch<R, std::decay_t<SwBase>, std::decay_t<T>, std::decay_t<F>> {
std::forward<SwBase>(swb),
std::forward<T>(t),
std::forward<F>(f),
};
}
template<typename R>
constexpr auto make_switch(char const* failMsg)
{
return [=](auto&&) -> R { throw std::out_of_range{ failMsg }; };
}
template<typename R, typename T, typename F, typename... Args>
constexpr auto make_switch(char const* failMsg, T&& val, F&& fn, Args&&... args)
{
return make_switch_impl<R>(
make_switch<R>(failMsg, std::forward<Args>(args)...),
std::forward<T>(val),
std::forward<F>(fn)
);
}
auto make_class(int i)
{
return make_switch<std::unique_ptr<Class>>(
"Asked to construct an unknown type",
0, [] { return std::make_unique<Class1>(); },
1, [] { return std::make_unique<Class2>(); }
)(i);
}
int main()
{
auto foo = make_class(1); // Make an object of type associated with the value 1
foo->func(); // Prints "Class2\n"
return 0;
}
The switch statement would turn into this:
auto make_class(int i)
{
return make_switch<std::unique_ptr<Class>>(
"Asked to construct an unknown type",
0, [] { return std::make_unique<Class1>(); },
1, [] { return std::make_unique<Class2>(); }
)(i);
}
You could also store the "switch" separately, although this makes it less optimizable (down to roughly the same level as François Andrieux's solution):
const auto mapName = make_switch<std::unique_ptr<Class>>(
"Asked to construct an unknown type",
0, [] { return std::make_unique<Class1>(); },
1, [] { return std::make_unique<Class2>(); }
);
auto make_class(int i)
{
return mapName(i);
}
This version, and also raw if-else chains, let the compiler optimize the make_class function to the equivalent of a switch statement. Also, the main function:
int main()
{
auto foo = make_class(1); // Make an object of type associated with the value 1
foo->func(); // Prints "Class2\n"
return 0;
}
Can be optimized to the equivalent of:
int main()
{
std::cout << "Class2\n";
return 0;
}
Whereas storing the std::function or the other less efficient tricks I've mentioned makes it much more difficult for the compiler to optimize it fully (I haven't found one that does).
Note that out of GCC, Clang, Visual C++, and the Intel compiler, only Clang was able to completely optimize the main function using this Switch struct. GCC and Visual C++ were able to optimize it to a call to Class2's func(). The Intel compiler doesn't seem to have optimized it at all (but maybe I don't know the right flags for it)

How to cast enums?

I have a third-party unscoped enum (that I can't modify) that I'd really like to cast to my own scoped enum. How can I provide something like a conversion operator?
What I'd like to do is something like this:
#include <iostream>
enum ThirdPartyLetter {
A=4,
B=5
};
enum class MyNumber {
ONE=1,
TWO=2
// This doesn't compile, of course
/*Number(const ThirdPartyLetter& rhs) {
if(rhs == ThirdPartyLetter::A) {
return ONE;
}
else {
return TWO;
}
}*/
};
int main() {
ThirdPartyLetter letter = ThirdPartyLetter::A;
MyNumber number = static_cast<MyNumber>(letter);
// Without the cast, this prints 4 (an invalid enum value!)
std::cout << int(number) << std::endl;
}
Is there a way to provide some kind of casting from ThirdPartyNumber to MyNumber?
An idiomatic way to do that at compile-time in C++ is using traits.
As an example:
enum Foo { ONE, TWO };
enum Bar { THREE, FOUR };
template<Foo> struct conv;
template<> struct conv<Foo::ONE> { static constexpr Bar value = Bar::THREE; };
template<> struct conv<Foo::TWO> { static constexpr Bar value = Bar::FOUR; };
If you want to do that at runtime, maybe a switch is well suited.
Anyway, you can still use traits to centralize your conversion logic and do something like this:
Bar get(Foo choice) {
switch(choice) {
case Foo::ONE:
return conv<ONE>::value;
case Foo::TWO:
return conv<TWO>::value;
}
}

How to pass template template parameter to template class without the underlying template parameter?

Take, for example, the following code:
// Say I have this class defined in some other file
class Foo;
// This class will act as a wrapper for an integer map
// to function pointers, which will create type TFoo objects
// depending on the given input (in this case a "const char*"
template<class TFoo>
struct Bar
{
typedef TFoo foo_t;
typedef TFoo (*get_foo_f_t)(const char*);
typedef std::unordered_map<int, get_foo_f_t> foo_handler_map_t;
Bar(const foo_handler_map_t& handlers)
: handlers_(handlers)
{
}
~Bar()
{
}
const foo_handler_map_t& handlers_;
};
// Now, this class will receive an _object_ of type
// "const Bar<T>&", which will have an already initialized
// map of integers to function pointers, different
// functions will be called with different input values
// via the public method, "action()".
template<class TFoo, const Bar<TFoo>& CBar>
class Quux
{
public:
Quux()
: bar_(CBar)
{
}
~Quux()
{
}
TFoo action(int a, const char* x)
{
auto it = this->bar_.handlers_.find(a);
if (it == this->bar_.handlers_.end())
{
// no handler defined for int `a'
return TFoo();
}
// i.e. CBar.handlers_[a](x)
return it->second(x);
}
private:
const Bar<TFoo>& bar_;
};
// Here is how the map of integers to function pointers
// will be initialized...
static std::unordered_map<int, Foo (*)(const char*)> handlers
{
{ 0, _hdl_0 }, // _hdl_* functions defined in different file
{ 1, _hdl_1 },
{ 2, _hdl_2 }
};
// And then passed to a "const Bar<T>" type object here
const Bar<Foo> bar (handlers);
int main()
{
// --> HERE IS WHAT I WANT TO CHANGE <--
Quux<decltype(bar)::foo_t, bar> quux;
// -------------------------------------
// Example (trivial) use of the 'quux' object
std::cout << quux.action(0, "abc").baz() << std::endl;
std::cout << quux.action(1, "def").baz() << std::endl;
std::cout << quux.action(2, "ghi").baz() << std::endl;
return 0;
}
Notice that the 'Quux' class takes two template parameters - one that is also a template parameter for the 'Bar' class, and a reference to a template object of type const Bar<T>, where T is any class related to 'Foo'. I would like to be able to do the following instead:
Quux<bar> quux;
Note: 'bar' is an object of type Bar<Foo>, but it should also be able to be any Bar<T> type.
Is this possible? I was thinking that maybe something like below could be used as a quick workaround, but I can't figure out what to put in place of /* ??? */:
template<const Bar</* ??? */>& CBar>
using Nuff = Quux<decltype(CBar)::foo_t, CBar>
Nuff<bar> nuff;
EDIT
I'm passing in a reference to an object to 'Quux' as a template parameter because copying would be inefficient (I think), rather than making a copy of the entire foo_handler_map_t object. I just want to be able to have a bunch of objects of type const Bar<T> that are defined globally in some namespace, and to be able to initialize 'Quux' objects like so:
namespace blah
{
std::unordered_map<int, /* funcptr type 0 */> _funcmap_0 { ... }
std::unordered_map<int, /* funcptr type 1 */> _funcmap_1 { ... }
...
const Bar<Foo0> FSET0 (_funcmap_0);
const Bar<Foo1> FSET1 (_funcmap_1);
...
}
int main()
{
Quux<blah::FSET0> a;
Quux<blah::FSET1> b;
...
return 0;
}
...And I do NOT want to pass it as a constructor argument.
The comments are very useful. However, if you wish to reduce the number of template arguments, you can pass the CBar as an argument to the constructor:
template<class TFoo>
class Quux
{
public:
Quux(const Bar<TFoo>& CBar)
: bar_(CBar)
{}
~Quux()
{}
TFoo action(int a, const char* x)
{
auto it = this->bar_.handlers_.find(a);
if (it == this->bar_.handlers_.end())
{
return TFoo();
}
return it->second(x);
}
private:
const Bar<TFoo>& bar_;
};
And define a function to create an instance of Quux:
template <typename TFoo>
auto make_Quux(const Bar<TFoo>& bar)
{
return Quux<TFoo>(bar);
}
Then in main(), you can use make_Quux():
int main()
{
auto quux = make_Quux(bar);
//...
}