我尝试创建一组类,以删除用于实现C ++游戏扩展的样板代码。对于这一点,我有一个指定的value
类,可容纳以下类型之一:float
,std::string
,bool
,std::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)
与function
和values
从方法发起获得char*
的方法和'char ** argv的+
INT ARGCfor values. The
执行method now is supposed to call the correct
method`实例功能
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_call
和call_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} }; }
};
假设一种检查值的当前类型的方法(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] 删除。
我来说两句