2016-12-16 58 views
0

我有一些靜態函數的類,並且包含指向這些函數的圖:PARAMS傳遞給可變參數函數通過函數指針改變它們的值

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調用函數指針時,這些值會改變。

任何想法我在做什麼錯在這裏?

+3

我沒有挖,但什麼是可能缺少的是'的std :: decay'的使用。總的來說,這不是一個好的編程習慣。非常不安全,容易出錯。通過設計合理的類層次結構,類似的東西甚至不應該編譯,除非所有類型都是正確的。您應該完全重新考慮您的方法,無論您嘗試解決什麼問題,並嘗試找出完全類型安全的解決方案。 –

+1

[關注@SamVarshavchik的評論]爲此,我建議你編輯你的問題,說明你實際上試圖解決的問題。 – Rerito

回答

2

你處於未定義行爲的荒野中。您的reinterpret_cast正在從無關的類型中投射,這很糟糕。除去這些強制轉換並使編譯器以其他方式開心。

+0

好吧,我有這些靜態函數,所有這些都返回'bool'。我需要通過某個名稱/鍵來調用它們,但是在運行時,它們是從文本文件(如小腳本)讀入的。他們有不同類型的paramteres數量。我還能如何解決這個問題,如果不是像我那樣通過函數指針? – Matthias

+0

您必須確保所有這些函數都具有相同的簽名(例如,接受某種變體對象),而不是使用指向此類型的指針,用數據和調用函數填充變體。基本上,代碼中不應該有reinterpret_cast。 – SergeyA

0

除非我誤解了我的意思,否則您想創建一個允許解析和比較不同類型的DSL。

這可以用boost::variant很容易完成。這只是一些樣板和定義不同類型比較操作的問題。

小而全例如:

#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