lundi 27 juin 2016

How can I avoid the void assignment in this code?

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.

Aucun commentaire:

Enregistrer un commentaire