通过函数指针传递给变差函数的参数会更改其值

Params passed to variadic function via function pointer change their value

本文关键字:函数 参数 指针      更新时间:2023-10-16

我有一个类,它包含一些静态函数和一个包含指向这些函数的指针的映射:

class Conditions
{
using cbType = bool(*)();
static std::unordered_map<std::string, cbType> const m_FunctionMap;
static bool Equal_int(const int A, const int B) { return A == B; }
static bool Equal_float(const float A, const float B) { return A == B; }
static bool Greater_int(const int A, const int B) { return A > B; }
static bool Greater_float(const float A, const float B) { return A > B; }
static bool Between_int(const int A, const int B, const int C) { return A > B && A < C; }
static bool Between_float(const float A, const float B, const float C) { return A > B && A < C; }
};

因此,静态函数可以具有不同类型的不同数量的参数。在.cpp文件中,我正在初始化映射:

std::unordered_map<std::string, Conditions::cbType> const Conditions::m_FunctionMap
{
{ "Equal_int", MakeMapVal(&Equal_int) },
{ "Equal_float", MakeMapVal(&Equal_float) },
{ "Greater_int", MakeMapVal(&Greater_int) },
{ "Greater_float", MakeMapVal(&Greater_int) },
{ "Between_int", MakeMapVal(&Between_int) },
{ "Between_float", MakeMapVal(&Between_float) },
};

然后,我在类Conditions中添加了一个方法,通过它们的名称来调用这些静态函数:

template <typename ... argsType>
static bool Call(std::string const& Key, argsType&& ... Args)
{
using prototype = bool(*)(argsType ...);
return reinterpret_cast<prototype>(m_FunctionMap.at(Key))(Args ...);
//return reinterpret_cast<prototype>(m_FunctionMap.at(Key))(std::forward<argsType>(Args) ...);  // this has the same issue
}

现在,当我运行此代码时,调用Call(std::string const& Key, argsType&& ... Args)方法,该方法正确地调用相应的静态函数。例如:

Call("Greater_int", 42, 40);

然而,在Greater_int()函数中,这两个参数不再是42和40,而是一些随机值。但在Call函数中,这些值正确地为4240。因此,当通过reinterpret_cast调用函数指针时,这些值会发生变化。

你知道我在这里做错了什么吗?

您正处于未定义行为的荒野中。您的reinterpret_cast是从不相关的类型进行强制转换的,这很糟糕。删除强制转换并通过其他方式使编译器满意。

除非我理解错误,否则您希望创建一个允许解析和比较不同类型的DSL。

使用CCD_ 9可以非常容易地实现这一点。这只是一些样板,是定义不同类型的比较操作的问题。

小型但完整的示例:

#include <boost/variant.hpp>
#include <boost/operators.hpp>
#include <string>
#include <iostream>
#include <iomanip>
// define the concept of equality in my scripting language
struct is_equal : boost::static_visitor<bool>
{
// x == x is easy
template<class T>
bool operator()(const T& l, const T& r) const {
return l == r;
}
// define the concept of comparing strings to integers
bool operator()(const std::string& l, const int& r) const {
return l == std::to_string(r);
}
// and integers to strings
bool operator()(const int& l, const std::string& r) const {
return (*this)(r, l);
}
};
struct is_less : boost::static_visitor<bool>
{
// x == x is easy
template<class T>
bool operator()(const T& l, const T& r) const {
return l < r;
}
// define the concept of comparing strings to integers
bool operator()(const std::string& l, const int& r) const {
return l < std::to_string(r);
}
// and integers to strings
bool operator()(const int& l, const std::string& r) const {
return (*this)(r, l);
}
};
struct emit : boost::static_visitor<std::ostream&>
{
emit(std::ostream& os) : os_(os) {}
// x == x is easy
template<class T>
std::ostream& operator()(const T& l) const {
return os_ << l;
}
std::ostream& operator()(const std::string& s) const {
return os_ << std::quoted(s);
}
std::ostream& os_;
};
struct scriptable_value
: boost::less_than_comparable<scriptable_value>
, boost::equality_comparable<scriptable_value>
{
using variant_type = boost::variant<std::string, int>;
scriptable_value(std::string v) : variant_(std::move(v)) {}
scriptable_value(int v) : variant_(v) {}
variant_type const& as_variant() const {
return variant_;
}
private:
variant_type variant_;
};
bool operator==(scriptable_value const& l, scriptable_value const& r)
{
return boost::apply_visitor(is_equal(), l.as_variant(), r.as_variant());
}
bool operator<(scriptable_value const& l, scriptable_value const& r)
{
return boost::apply_visitor(is_less(), l.as_variant(), r.as_variant());
}
std::ostream& operator<<(std::ostream& os, scriptable_value const& r)
{
return boost::apply_visitor(emit(os), r.as_variant());
}

int main()
{
auto x = scriptable_value(10);
auto y = scriptable_value("10");
auto x2 = scriptable_value(9);
auto y2 = scriptable_value("9");
std::cout << x << " == " << y << " : " << std::boolalpha << (x == y) << std::endl;
std::cout << x << " != " << y << " : " << std::boolalpha << (x != y) << std::endl;
std::cout << x << " == " << y2 << " : " << std::boolalpha << (x == y2) << std::endl;
std::cout << x << " != " << y2 << " : " << std::boolalpha << (x != y2) << std::endl;
std::cout << x << " <  " << y << " : " << std::boolalpha << (x < y) << std::endl;
std::cout << x << " >= " << y << " : " << std::boolalpha << (x >= y) << std::endl;
std::cout << x << " <  " << y2 << " : " << std::boolalpha << (x < y2) << std::endl;
std::cout << x << " >= " << y2 << " : " << std::boolalpha << (x >= y2) << std::endl;
std::cout << x << " == " << x2 << " : " << std::boolalpha << (x == x2) << std::endl;
std::cout << x << " != " << x2 << " : " << std::boolalpha << (x != x2) << std::endl;
}

预期输出:

10 == "10" : true
10 != "10" : false
10 == "9" : false
10 != "9" : true
10 <  "10" : false
10 >= "10" : true
10 <  "9" : false
10 >= "9" : true
10 == 9 : false
10 != 9 : true