- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我正在编写的一些代码中,我有一堆 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 错误信号。
那部分正在工作,有一些工作,这个问题不是关于如何做到这一点。 (请不要告诉我有关 luabind
、 luabridge
或其他现有库的信息,因为我无法深入了解这些不适合我的项目的原因。)
相反,我现在遇到的问题是,有时我希望输入参数具有略微不同的语义。
例如,有时参数应该是可选的。我将模板专门用于 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 中,值 false
和 nil
是假的,所有其他值都是真值。
通常,当您有一个接受 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/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!