gpt4 book ai didi

c++ - 将 "policy"附加到函数参数

转载 作者:行者123 更新时间:2023-11-30 05:26:01 24 4
gpt4 key购买 nike

在我正在编写的一些代码中,我有一堆 C++ 函数,我试图以通用方式绑定(bind)到 lua。 (不过,这道题真的和lua没关系,真的是一道C++设计题。)

我的想法是我可能有一个带有签名的 C++ 函数

int my_function(lua_State * L, std::string server, std::string message);

例如,我希望能够将其推送到 lua 并将其公开给用户脚本。

但是lua只能直接接收签名int (lua_State *)的函数.所以,我有一些模板,它们采用带有上述签名的函数指针,并生成一个签名函数 int(lua_State *) ,它会尝试从 lua 堆栈中读取相应的参数,如果成功则使用参数调用目标函数,如果失败则向用户发出 lua 错误信号。

那部分正在工作,有一些工作,这个问题不是关于如何做到这一点。 (请不要告诉我有关 luabindluabridge 或其他现有库的信息,因为我无法深入了解这些不适合我的项目的原因。)

相反,我现在遇到的问题是,有时我希望输入参数具有略微不同的语义。

例如,有时参数应该是可选的。我将模板专门用于 boost::optional为了处理那个案子。所以我可以用 boost::optional 标记可选参数在函数签名中,包装器将知道如果缺少该参数,这不是错误,它应该传递 boost::none。 .示例:

int my_function(lua_State * L, boost::optional<std::string>, std::string message);

所以 boost::optional模板的使用有点像此处输入的“策略”,我基本上喜欢它的工作原理。

这里有一个我不太确定的问题:处理 bool .在lua中,有一个合适的boolean类型,然而,lua 也有一个概念 contextually boolean ,类似于 C++ 的 contextually convertible to bool 概念.在 lua 中,值 falsenil是假的,所有其他值都是真值。

通常,当您有一个接受 bool 的 c++ 函数时, 用户会期望他们可以传递任何值并且您的界面将遵守 truthiness即使它不是严格意义上的 bool 值。但是,在其他情况下,您可能真的希望将其严格解释为 bool。 , 如果他们没有通过 true 则为用户错误或 false .

我希望能够做的是在函数声明中标记“严格”策略,所以它看起来像

int my_function(lua_State * L, strict<bool> b, std::string message);

在哪里,strict是一些类似的模板

template <typename T>
struct strict {
T value;
};

而且这个模板只在我的包装机中才真正有意义。

令人讨厌的是你必须输入 b.value无处不在。

我想过这样做:

template <typename T>
struct strict {
T value;

operator T & () & { return this->value; }
operator const T & () const & { return this->value; }
operator T && () && { return std::move(this->value); }
};

允许从 strict<T> 进行一系列引用限定的隐式转换对值的引用。

这有多不安全?虽然我一直坚持“隐式转换是邪恶的”这句口头禅,但我看不出其中存在重大安全漏洞。我在测试代码中尝试了一下,它似乎没有产生歧义或问题,但可能有一种聪明的方法可以让它做一些我没有想到的非常糟糕的事情。

如果这不是一个好主意,有没有比输入 b.value 更好的策略?无处不在,还是以某种不同的方式来设置不会干扰类型的参数策略?

最佳答案

像这样的东西应该可以做到。

visit 的重载就是完成这项工作的。请注意来自 optional 版本的递归调用。

#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
#include <boost/optional.hpp>

// some boilerplate

template <typename T, template <typename, typename...> class Tmpl> // #1 see note
struct is_derived_from_template
{
typedef char yes[1];
typedef char no[2];

static no & test(...);

template <typename ...U>
static yes & test(Tmpl<U...> const &);

static bool constexpr value = sizeof(test(std::declval<T>())) == sizeof(yes);
};
template<typename T, template <typename, typename...> class Tmpl>
static constexpr bool is_derived_from_template_v = is_derived_from_template<T, Tmpl>::value;


// i dont know much about a lua_state but I guess it's a bit like this...
struct lua_state {
void set_string(std::size_t index, const std::string& s) {
std::cout << "index " << index << " setting string " << std::quoted(s) << std::endl;
}
void set_missing(std::size_t index) {
std::cout << "index " << index << " setting missing" << std::endl;
}
void set_int(std::size_t index, int i) {
std::cout << "index " << index << " setting int " << i << std::endl;
}
};

// policies

template<class T, std::enable_if_t<std::is_same<std::decay_t<T>, std::string>::value>* = nullptr>
void visit(std::size_t index, lua_state* pstate, T&& value)
{
pstate->set_string(index, std::forward<T>(value));
}

template<class T, std::enable_if_t<std::is_same<std::decay_t<T>, int>::value>* = nullptr>
void visit(std::size_t index, lua_state* pstate, T&& value)
{
pstate->set_int(index, std::forward<T>(value));
}

// special policy for optional
template<class T,
std::enable_if_t<is_derived_from_template_v<std::decay_t<T>, boost::optional>>* = nullptr>
void visit(std::size_t index, lua_state* pstate, T&& value)
{
if (value)
{
visit(index, pstate, std::forward<T>(value).value());
}
else {
pstate->set_missing(index);
}
}

// helper function

template<std::size_t...Is, class Tuple>
void set_vars_impl(lua_state* pstate, std::index_sequence<Is...>, Tuple&& tuple)
{
using expand = int [];
void(expand{ 0,
((visit(Is, pstate, std::get<Is>(std::forward<Tuple>(tuple)))),0)...
});
}

template<class...Ts>
void set_vars(lua_state* pstate, Ts&&...ts)
{
set_vars_impl(pstate,
std::make_index_sequence<sizeof...(Ts)>(),
std::make_tuple(std::forward<Ts>(ts)...));
}

int main(int argc, const char * argv[]) {

lua_state ls;

boost::optional<std::string> a { };
boost::optional<std::string> b { std::string { "hello" }};
std::string c = "world";

int d = 0;
boost::optional<int> e;
boost::optional<int> f { 1 };

set_vars(std::addressof(ls), a, b, c, d, e, f);


return 0;
}

预期结果:

index 0 setting missing
index 1 setting string "hello"
index 2 setting string "world"
index 3 setting int 0
index 4 setting missing
index 5 setting int 1

关于c++ - 将 "policy"附加到函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38002402/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com