How can I avoid the void assignment in this code?

NeomerArcana

I have a VariantType that can be empty, i.e. has a void state.

The following code, when compiling with Mingw Builds x64 5.3.0 generates the error:

error: conversion from 'void' to non-scalar type 'VariantType {aka utils::Variant<bool, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >}' requested|

How can I avoid the error:

#include <Common/Variant.hpp>
using namespace utils;

#include <vector>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <map>

using VariantType = Variant<bool,int,std::string>;

class EFBase
{
public:
    virtual ~EFBase() {}
};

template<typename FuncSig>
class EF : public EFBase
{
public:

    EF(std::function<FuncSig> func) : m_function(func) {};

    std::function<FuncSig> m_function;
};

class Functions
{
public:

    using FuncMap = std::map<std::string,EFBase*>;

    FuncMap m_functions;

    template<typename FuncType>
    void Add(const std::string name, FuncType function)
    {
        m_functions.emplace(FuncMap::value_type(name,new EF<FuncType>(std::function<FuncType>(function))));
    }

    template<typename... Args>
    VariantType Invoke(const std::string& name, Args... args)
    {
        auto itr = m_functions.find(name);
        if(itr == m_functions.end())
            return VariantType();

        typedef void Func(typename std::remove_reference<Args>::type...);
        std::type_index index(typeid(Func));

        const EFBase& a = *itr->second;
        std::function<Func> func = static_cast<const EF<Func>&>(a).m_function;
        if(typeid(typename std::function<Func>::result_type) == typeid(void))
        {
            func(std::forward<Args>(args)...);
            return VariantType();
        }
        else
        {
            VariantType x = func(std::forward<Args>(args)...);
            return x;
        }
    }
};

int main()
{
    Functions f;
    f.Add<int(bool)>("get3",[](bool x) { return 3; });

    VariantType v = f.Invoke<>("get3",true);

    return 0;
}

I would've thought that the check for the result_type of the function object would have been enough; but I guess it's not because of the template instantiation. Do I need a sort of helper struct that does something different in a void case (based on template params)?

The purpose of the code is to store functions of arbitrary signature in a map by name so that they can be called upon later. The VariantType handles the multiple possible return values.

The error is on the assignment in the else block of the Invoke method.

The VariantType is a fair bit of code, so I didn't provide it (I'm not sure it's pertinent anyway). But I can if needed.

mkal

Depending on the exact use case, one suggestion would be to store std::function<VariantType(x)>s in the map (with x being some fixed set of parameters), with the idea that the functions will be adapted to a particular signature using functor wrappers for storage. The client's functions passed to Add would then either (a) need to be wrapped in functors that have the correct signature, or (b) if you know all of the different kinds of functions that will ever be passed to Add, you could define template<typename F, typename ...Args> Add(F f), and specialize it based on std::result_of<F(...Args)> so that Add could make the wrappers. You could also do a mixed approach and require that the clients pass functions that conform to the fixed parameter list and Add can wrap those functions to return VariantTypes based on the passed-in function's return type.

An example is below showing some of the concepts.

Note the SFINAE principle being applied to the wrapper template overloads to avoid having the compiler fail in the specialization that we don't want it to evaluate (the one where f returns void).

Also note that I think a situation where you actually need to dispatch different argument lists at runtime depending on the type of function may be a lot more difficult, hence the approach here tries to normalize the argument lists by capturing them when creating the callback. If you really think you need the variadic argument list in Invoke, then I would suggest maybe looking into using boost::any to wrap the functions, or at least for conceptual guidance.

#include <iostream>
#include <type_traits>
#include <functional>
#include <string>
#include <map>
#include <vector>

template<typename T1, typename T2, typename T3>
struct Variant
{
    Variant() { std::cout << "In void Ctor of Variant" << std::endl; }
    template<typename T> Variant(T t) { std::cout << "In data Ctor of Variant" << std::endl; }
};

using VariantType = Variant<bool,int,std::string>;
using FuncSig = std::function<VariantType(int)>;


struct Functions
{
    template<typename F, typename Result = typename std::result_of<F(int)>::type >
    void Add(const std::string name, F f)
    {
        this->m_functions.emplace(name, [=](int i) { return wrapper<F, Result>(f, i); });
    }

    VariantType Invoke(const std::string& name, int i)
    {
        auto itr = m_functions.find(name);
        if(itr == m_functions.end())
            return VariantType();

        return itr->second(i);
    }
private:
    using FuncMap = std::map<std::string,FuncSig>;
    FuncMap m_functions;

    template<typename F, typename ReturnValue, typename ...Args>
    static typename std::enable_if<!std::is_same<ReturnValue, void>::value, VariantType>::type wrapper(F f, Args&&... args)
    {
        VariantType x = f(std::forward<Args>(args)...);
        return x;
    }

    template<typename F, typename ReturnValue, typename ...Args>
    static typename std::enable_if<std::is_same<ReturnValue, void>::value, VariantType>::type wrapper(F f, Args&&... args)
    {
        f(std::forward<Args>(args)...);
        return VariantType();
    }
};

struct Client
{
    Client(Functions& funcs)
    {
        funcs.Add("v_func", [&](int i) { this->v_func(this->d, i); } );
        funcs.Add("b_func", [&](int i) { return this->b_func(i); } );
        funcs.Add("s_func", [&](int i) { return this->s_func(i, this->some_string); } );
        funcs.Add("i_func", [&](int i) { return this->i_func(i); } );
    }

    void v_func(double d, int i) const { std::cout << this->obj_name << ": v_func()" << d << ", " << i << std::endl; }
    bool b_func(int i) const { std::cout << this->obj_name << ": b_func()" << i << std::endl; return i > 5; }
    std::string s_func(int i, std::string const& s) const { std::cout << this->obj_name << ": s_func()" << i << ", " << s << std::endl; return s; }
    int i_func(int i) const { std::cout << this->obj_name << ": i_func()" << i << std::endl; return i + 10; }

    std::string obj_name;
    const std::string some_string = "some_string";
    const double d = 3.14;
};

int main()
{
    VariantType variant;
    Functions functions;
    Client c(functions);
    c.obj_name = "Client1";
    std::vector<std::string> v = { "s_func", "b_func", "v_func", "i_func" };
    int i = 0;
    for (auto s : v) { variant = functions.Invoke(s, i++); }

    return 0;
}

outputs:

In void Ctor of Variant
Client1: s_func()0, some_string
In data Ctor of Variant
Client1: b_func()1
In data Ctor of Variant
Client1: v_func()3.14, 2
In void Ctor of Variant
Client1: i_func()3
In data Ctor of Variant

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How can I avoid this "variable referenced before assignment"?

From Dev

How(and why) can I avoid returning a void on these async methods?

From Dev

How can I avoid code duplication?

From Dev

How can I avoid this code duplication?

From Dev

How can I avoid this code duplication?

From Dev

How can I fix this error in my code for an assignment?

From Java

How can I avoid repeating code initializing a hashmap of hashmap?

From Dev

Kotlin: How can I avoid code duplication in constructors?

From Dev

How can I avoid code repetition with enums in C#?

From Dev

How can I avoid repeating code initializing a hashmap of hashmap?

From Dev

How can I avoid the duplicate code of mapping in Spring project?

From Dev

How can I avoid repeating code initializing a hashmap of hashmap?

From Dev

How can I avoid code repetition with enums in C#?

From Dev

How can I consolidate this code to avoid multiple #temp table writes?

From Dev

CRTP to avoid code duplication : can't assignment Base=Derived by value

From Dev

how can I use void** function(void**)

From Dev

How can I avoid this NullPointerException?

From Dev

How can I accelerate the array assignment in python?

From Dev

How can I overload the assignment operation in Rust?

From Dev

How can I debug the assignment of an object to a class?

From Java

How can I avoid duplicate code with the same method body but different return types in Java?

From Java

How can I avoid Java code in JSP files, using JSP 2?

From Dev

How can I avoid running this jQuery code when clicking on a hyperlink inside an html table?

From Dev

How can I avoid repeating my code when creating reply callbacks in NodeJS?

From Dev

How can I avoid filling my JavaScript code with type-checking logic when using dependency injection?

From Dev

How can I avoid migrations using Entity Framework Code First with Existing Database?

From Dev

How can I test void methods?

From Dev

How can I implement a void* in golang?

From Dev

What is the (void*) type? And how can I dereference it?

Related Related

  1. 1

    How can I avoid this "variable referenced before assignment"?

  2. 2

    How(and why) can I avoid returning a void on these async methods?

  3. 3

    How can I avoid code duplication?

  4. 4

    How can I avoid this code duplication?

  5. 5

    How can I avoid this code duplication?

  6. 6

    How can I fix this error in my code for an assignment?

  7. 7

    How can I avoid repeating code initializing a hashmap of hashmap?

  8. 8

    Kotlin: How can I avoid code duplication in constructors?

  9. 9

    How can I avoid code repetition with enums in C#?

  10. 10

    How can I avoid repeating code initializing a hashmap of hashmap?

  11. 11

    How can I avoid the duplicate code of mapping in Spring project?

  12. 12

    How can I avoid repeating code initializing a hashmap of hashmap?

  13. 13

    How can I avoid code repetition with enums in C#?

  14. 14

    How can I consolidate this code to avoid multiple #temp table writes?

  15. 15

    CRTP to avoid code duplication : can't assignment Base=Derived by value

  16. 16

    how can I use void** function(void**)

  17. 17

    How can I avoid this NullPointerException?

  18. 18

    How can I accelerate the array assignment in python?

  19. 19

    How can I overload the assignment operation in Rust?

  20. 20

    How can I debug the assignment of an object to a class?

  21. 21

    How can I avoid duplicate code with the same method body but different return types in Java?

  22. 22

    How can I avoid Java code in JSP files, using JSP 2?

  23. 23

    How can I avoid running this jQuery code when clicking on a hyperlink inside an html table?

  24. 24

    How can I avoid repeating my code when creating reply callbacks in NodeJS?

  25. 25

    How can I avoid filling my JavaScript code with type-checking logic when using dependency injection?

  26. 26

    How can I avoid migrations using Entity Framework Code First with Existing Database?

  27. 27

    How can I test void methods?

  28. 28

    How can I implement a void* in golang?

  29. 29

    What is the (void*) type? And how can I dereference it?

HotTag

Archive