如何正确组合类型别名、函数指针和模板函数
How to correctly combine type aliases, function pointers, and template functions
我在 .h 文件中声明了以下 class:
class BeliefCondFunc
{
private:
using funcTypeBool = bool(*)(const bool&, const std::list<bool>&, const std::vector<bool>&);
using funcTypeInt = bool(*)(const int&, const std::list<int>&, const std::vector<int>&);
using funcTypeFloat = bool(*)(const float&, const std::list<float>&, const std::vector<float>&);
using funcTypeString = bool(*)(const std::string&, const std::list<std::string>&, const std::vector<std::string>&);
static std::unordered_map<std::string, funcTypeBool> const m_FunctionMapBool;
static std::unordered_map<std::string, funcTypeInt> const m_FunctionMapInt;
static std::unordered_map<std::string, funcTypeFloat> const m_FunctionMapFloat;
static std::unordered_map<std::string, funcTypeString> const m_FunctionMapString;
template <typename T>
static bool Greater(const T& Fact, const std::list<T>& Facts, const std::vector<T>& Params)
{
return Params.empty() ? false : (Fact > Params[0]);
}
public:
template <typename T>
static bool Call(const std::string FuncName, const T& Fact, const std::list<T>& Facts, const std::vector<T>& Params)
{
if(typeid(T) == typeid(int))
return m_FunctionMapInt.find(FuncName) != m_FunctionMapInt.end() ? (*m_FunctionMapInt.at(FuncName))(Fact, Facts, Params) : false;
return false;
}
};
在 .cpp 文件中,我定义了 const
函数映射,如下所示:
std::unordered_map<std::string, BeliefCondFunc::funcTypeInt> const BeliefCondFunc::m_FunctionMapInt
{
{ "Greater", &Greater<int> },
};
但是,当我尝试编译此代码时,我收到以下关于在 Call()
方法中调用函数指针的错误:
error C2664: 'bool (const int &,const std::list<int,std::allocator<_Ty>> &,const std::vector<_Ty,std::allocator<_Ty>> &)': cannot convert argument 3 from 'const std::vector<std::string,std::allocator<_Ty>>' to 'const std::vector<int,std::allocator<_Ty>> &'*
知道我做错了什么吗?
你需要constexpr if
。当您为每种类型实例化您的函数时,它仍然会尝试为模板中的每个语句创建代码,即使它不是针对每种类型。对于 std::string
:
if(typeid(std::string) == typeid(int))
return m_FunctionMapInt.find(FuncName) != m_FunctionMapInt.end() ? (*m_FunctionMapInt.at(FuncName))(Fact, Facts, Params) : false;
这会导致您的错误,因为您无法将 std::string
传递给整数映射函数。
正如 Mikel F 提到的,问题是 if
语句主体中的部分必须编译,即使它从未被调用。该语句(概念上)是运行时检查,因此两个分支都必须在编译时有效。
要解决这个问题(只要你没有c++17编译器可用),你可以写两个版本:
- 采用任何 T 且始终 returns false
的通用模板函数
T==int
的专用版本,将调用整数并在 if
语句的正文中使用公式:
示例*:
template <typename T>
static bool Call(const std::string FuncName, const T& Fact, const std::list<T>& Facts, const std::vector<T>& Params)
{
return false;
}
template <>
static bool Call<int>(const std::string FuncName, const int& Fact, const std::list<int>& Facts, const std::vector<int>& Params)
{
return m_FunctionMapInt.find(FuncName) != m_FunctionMapInt.end() ? (*m_FunctionMapInt.at(FuncName))(Fact, Facts, Params) : false;
}
*) 我没有将代码通过编译器,所以它可能包含拼写错误。
我在 .h 文件中声明了以下 class:
class BeliefCondFunc
{
private:
using funcTypeBool = bool(*)(const bool&, const std::list<bool>&, const std::vector<bool>&);
using funcTypeInt = bool(*)(const int&, const std::list<int>&, const std::vector<int>&);
using funcTypeFloat = bool(*)(const float&, const std::list<float>&, const std::vector<float>&);
using funcTypeString = bool(*)(const std::string&, const std::list<std::string>&, const std::vector<std::string>&);
static std::unordered_map<std::string, funcTypeBool> const m_FunctionMapBool;
static std::unordered_map<std::string, funcTypeInt> const m_FunctionMapInt;
static std::unordered_map<std::string, funcTypeFloat> const m_FunctionMapFloat;
static std::unordered_map<std::string, funcTypeString> const m_FunctionMapString;
template <typename T>
static bool Greater(const T& Fact, const std::list<T>& Facts, const std::vector<T>& Params)
{
return Params.empty() ? false : (Fact > Params[0]);
}
public:
template <typename T>
static bool Call(const std::string FuncName, const T& Fact, const std::list<T>& Facts, const std::vector<T>& Params)
{
if(typeid(T) == typeid(int))
return m_FunctionMapInt.find(FuncName) != m_FunctionMapInt.end() ? (*m_FunctionMapInt.at(FuncName))(Fact, Facts, Params) : false;
return false;
}
};
在 .cpp 文件中,我定义了 const
函数映射,如下所示:
std::unordered_map<std::string, BeliefCondFunc::funcTypeInt> const BeliefCondFunc::m_FunctionMapInt
{
{ "Greater", &Greater<int> },
};
但是,当我尝试编译此代码时,我收到以下关于在 Call()
方法中调用函数指针的错误:
error C2664: 'bool (const int &,const std::list<int,std::allocator<_Ty>> &,const std::vector<_Ty,std::allocator<_Ty>> &)': cannot convert argument 3 from 'const std::vector<std::string,std::allocator<_Ty>>' to 'const std::vector<int,std::allocator<_Ty>> &'*
知道我做错了什么吗?
你需要constexpr if
。当您为每种类型实例化您的函数时,它仍然会尝试为模板中的每个语句创建代码,即使它不是针对每种类型。对于 std::string
:
if(typeid(std::string) == typeid(int))
return m_FunctionMapInt.find(FuncName) != m_FunctionMapInt.end() ? (*m_FunctionMapInt.at(FuncName))(Fact, Facts, Params) : false;
这会导致您的错误,因为您无法将 std::string
传递给整数映射函数。
正如 Mikel F 提到的,问题是 if
语句主体中的部分必须编译,即使它从未被调用。该语句(概念上)是运行时检查,因此两个分支都必须在编译时有效。
要解决这个问题(只要你没有c++17编译器可用),你可以写两个版本:
- 采用任何 T 且始终 returns false 的通用模板函数
T==int
的专用版本,将调用整数并在if
语句的正文中使用公式:
示例*:
template <typename T>
static bool Call(const std::string FuncName, const T& Fact, const std::list<T>& Facts, const std::vector<T>& Params)
{
return false;
}
template <>
static bool Call<int>(const std::string FuncName, const int& Fact, const std::list<int>& Facts, const std::vector<int>& Params)
{
return m_FunctionMapInt.find(FuncName) != m_FunctionMapInt.end() ? (*m_FunctionMapInt.at(FuncName))(Fact, Facts, Params) : false;
}
*) 我没有将代码通过编译器,所以它可能包含拼写错误。