将std :: variant的包装器的std :: vector传递给可变参数类,在不知道具体细节的情况下包装可变参数方法

X39

目标

我尝试创建一组类,以删除用于实现C ++游戏扩展的样板代码。对于这一点,我有一个指定的value类,可容纳以下类型之一:floatstd::stringboolstd::vector<value>void

为此,我想要一个host可以添加一个或多个method实例的类,如下所示:

using namespace std::string_literals;
host h;
h.add(
    method<bool, req<std::string>, req<std::string>, opt<bool>>("compare_strings"s,
        [](std::string s_orig, std::string s_comp, std::optional<bool> ingore_case) -> bool {
            if (ignore_case.has_value() && ignore_case.value()) {
                // ... lowercase both
            }
            return s_orig.compare(s_comp) == 0;
        }));

请注意,req<T>应该是要求给定值opt<T>的元信息,而不要求给定值的元信息,并且只能在所有必需参数之后提供。

host类现在包含的方法execute(std::string function, std::vector<value> values)functionvalues从方法发起获得char*的方法和'char ** argv的+ INT ARGCfor values. The执行method now is supposed to call the correctmethod`实例功能

value host::execute(std::string function, std::vector<value> values) {
    // get matching method group
    std::vector<method> mthds = m_methods[function];
    
    // get matching parameter list
    for (method& mthd : mthds) {
        if (mthd.can_call(mthds, values)) {
            // call generic method
            auto res = mthd.call_generic(values);
            
            // pass result back to callee
            // return [...]
        }
    }
    // return error back to callee
    // return [...]
}

这意味着实际的method类现在需要正确处理两个方法can_callcall_generic

value班有相应template<typename T> bool is()template<typename T> T get()方法。

剩下什么

我确实有其他尝试,但是由于失败,我删除了它们(后方不是很聪明,但是由于另一个人依靠结果起作用,因此需要将整个过程弄清楚),现在无法找出之前的另一种尝试。 ..所以这就是我现在所剩下的:

class method_base
{
public:
    template<typename T> struct in { using type = T; };
    template<typename T> struct opt { using type = T; };
public:
    virtual bool can_call(std::vector<sqf::value> values) = 0;
    virtual sqf::value call_generic(std::vector<sqf::value> values) = 0;
};

template<typename T, typename ... TArgs>
class method : public method_base
{
    func m_func;

    sqf::value val
public:
    using func = T(*)(TArgs...);
    method(func f) : m_func(f) {}


    virtual retval can_call(std::vector<sqf::value> values) override
    {

    }
};

附录

如果有不清楚的地方,令人困惑的地方,或者您还有其他问题,请务必询问他们。我会尽力改写任何不清楚的地方,因为这将在将来开发进一步的扩展时大有帮助,可能会定义一种“ go to”方式,以便在相关游戏中为社区创建扩展(Arma 3以防万一。有人想知道)

我可能会注意到,这几乎是我对元编程的第一次深入研究,因此我呈现的内容可能根本不可能。如果是这样,我谨问您是否也可以解释为什么会这样,而我尝试做的事情是不可能的。


解决方案

我确实要感谢所有再次回答这个问题的人。我最终在这里结合了所有解决方案的大部分内容,并且在此过程中学到了很多东西。我最终得到的最终实现如下所示:

namespace meta
{
    template <typename ArgType>
    struct is_optional : std::false_type {};
    template <typename T>
    struct is_optional<std::optional<T>> : std::true_type {};
    template <typename ArgType>
    inline constexpr bool is_optional_v = is_optional<ArgType>::value;

    template <typename ArgType>
    struct def_value { static ArgType value() { return {}; } };

    template <typename ArgType>
    struct get_type { using type = ArgType; };
    template <typename ArgType>
    struct get_type<std::optional<ArgType>> { using type = ArgType; };
}
struct method {
    std::function<bool(const std::vector<value>&)> m_can_call;
    std::function<value(const std::vector<value>&)> m_call;

    template <typename ... Args, std::size_t... IndexSequence>
    static bool can_call_impl(const std::vector<value>& values, std::index_sequence<IndexSequence...> s) {
        // values max args
        return values.size() <= sizeof...(Args) && 
            // for every Arg, either...
            (... && (
            // the value provides that argument and its the correct type, or...
            (IndexSequence < values.size() && sqf::is<sqf::meta::get_type<Args>::type>(values[IndexSequence])) ||
            // the value does not provide that argument and the arg is an optional
            (IndexSequence >= values.size() && sqf::meta::is_optional_v<Args>)
            ));
    }

    template <typename Ret, typename ... Args, std::size_t... IndexSequence>
    static value call_impl(std::function<Ret(Args...)> f, const std::vector<value>& values, std::index_sequence<IndexSequence...>) {
        return {
            // call the function with every type in the value set,
            // padding with empty std::optionals otherwise
            std::invoke(f,
                (IndexSequence < values.size() ? sqf::get<sqf::meta::get_type<Args>::type>(values[IndexSequence])
                                    : sqf::meta::def_value<Args>::value())...)
        };
    }

public:
    template <typename Ret, typename ... Args>
    method(std::function<Ret(Args...)> f) :
        m_can_call([](const std::vector<value>& values) -> bool
            {
                return can_call_impl<Args...>(values, std::index_sequence_for<Args...>{});
            }),
        m_call([f](const std::vector<value>& values) -> value
            {
                return call_impl<Ret, Args...>(f, values, std::index_sequence_for<Args...>{});
            })
    {
    }

    bool can_call(const std::vector<value>& values) const { return m_can_call(values); }

    value call_generic(const std::vector<value>& values) const { return m_call(values); }

    // to handle lambda
    template <typename F>
    method static create(F f) { return method{ std::function{f} }; }
};
贾罗德42

假设一种检查值的当前类型的方法(template <typename T> bool value::isA<T>())和一种检索值的方法(template <typename T> /*const*/T& get(/*const*/ value&)

看来您可以这样做:

struct method
{
    template <typename Ret, typename ... Ts>
    method(std::function<Ret(Ts...)> f) : method(std::index_sequence<sizeof...(Ts)>(), f)
    {}

    template <typename Ret, typename ... Ts, std::size_t ... Is>
    method(std::index_sequence<Is...>, std::function<Ret(Ts...)> f) :
        isOk([](const std::vector<value>& values) {
            return ((values.size() == sizeof...(Is)) && ... && values[Is].isA<Ts>());
        }),
        call([f](const std::vector<value>& values){
            return f(get<Ts>(values[Is])...);
        })
    {}

    // to handle lambda
    template <typename F>
    static fromCallable(F f) { return method{std::function{f}}; }

    std::function<bool(const std::vector<value>&)> isOk;
    std::function<value(const std::vector<value>&)> call;
};

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章