二义性调用:int到double或bool

Ambiguous call: int to double or bool

本文关键字:double bool int 调用 二义性      更新时间:2023-10-16

我有一个Parameter类,并且我重载了构造函数来接受bool或double。当你给它一个int时,它无法构建:

错误C2668: 'Parameter::Parameter':对重载的二义调用函数可以是的参数:参数(std:: string, std:: string,双)"或
的参数:参数(std:: string, std:: string, bool)"

我想我有两个选择:

  1. 使用int default重载
  2. 显式地将变量转换为双变量

我有大量的参数,其中一些是无符号长,浮点数等(在一个多人支持的项目中),所以这些都不是完美的解决方案。有没有办法强制从int型到double型的隐式转换?谢谢。

代码:

#include <string>
#include <unordered_map>
using namespace std;
class Parameter
{
public:
    enum eVarType { BOOL, NUMBER};
    Parameter() {};
    Parameter( string param_name, string param_description, bool dft ) { type_ = BOOL;};
    Parameter( string param_name, string param_description, double dft ) { type_ = NUMBER;};
private:
    eVarType type_;
};
class ParameterManager
{
public:
    template<typename T> void add( string option_name, string description, T value );
private:
    std::unordered_map< string, Parameter > parameters;
};
template<typename T> void ParameterManager::add( string param, string description, T value )
{
    parameters[param] = Parameter( param, description, value );
};
int main()
{
    ParameterManager mgr;
    int var = 1;
    mgr.add("number","This is an int",var); //Could be double or bool: I want it to be a double
}

如果您想从考虑中删除具有bool final元素的元素,除非它是显式的bool,请考虑模板和SFINAE:

template<class X>
Parameter( string , string , X  ,
    enable_if_t<is_same<decay_t<X>, bool>::value, int> = 0)
{ type_ = BOOL;}

参见coliru的上下文。

或者在模板参数列表中执行SFINAE:

template<class X,
    enable_if_t<is_same<decay_t<X>, bool>::value, nullptr_t> = nullptr>
Parameter( string , string , X ) { type_ = BOOL;}

不含enable_if_tdecay_t:

template<class X>
Parameter( string , string , X ,
    typename enable_if<is_same<typename decay<X>::type,
    bool>::value, int>::type = 0)
{ type_ = BOOL;}
template<class X,
    typename enable_if<is_same<typename decay<X>::type,
    bool>::value, nullptr_t>::type = nullptr>
Parameter( string , string , X)
{ type_ = BOOL;}

您可以使用trait模板来实现这一点,以便对double进行适当的强制转换。

#include <string>
#include <unordered_map>
using namespace std;
class Parameter
{
public:
    enum eVarType { BOOL, NUMBER };
    Parameter() {};
    Parameter(string param_name, string param_description, bool dft) { type_ = BOOL; };
    Parameter(string param_name, string param_description, double dft) { type_ = NUMBER; };
private:
    eVarType type_;
};
// Traits definitions.
template<typename T> struct DFTtrait;
template<> struct DFTtrait<double> 
{typedef double Type;};
template<> struct DFTtrait<bool>
{typedef bool Type;};
// Here is the key. When it receives an int
// the type is set to double.
template<> struct DFTtrait<int>
{typedef double Type;};

class ParameterManager
{
public:
    template<typename T, typename cast_t = DFTtrait<T>::Type> void add(string option_name, string description, T value);
private:
    std::unordered_map< string, Parameter > parameters;
};
template<typename T, typename cast_t> void ParameterManager::add(string param, string description, T value)
{
    parameters[param] = Parameter(param, description, (cast_t)value);
};

int main()
{
    ParameterManager mgr;
    int var = 1;
    mgr.add("number", "This is an int", var); // Now DFTtrait<T>::Type is evaluated to double
                                              // hence, (cast_t)value == (double)value when T == int
}

这对于您的场景来说是完美的:我有大量的参数,其中一些是无符号长,浮点数等…很容易添加更多的特征(DFTtrait实现)来满足您的所有需求,例如,如果您添加:

template<> struct DFTtrait<long long int>
{typedef double Type;};

您的代码将自动支持long long int并正确地转换为double

一个非常简单的版本是为构造函数使用模板形参,对bool(以及任何其他不想转换为double的类型)使用非模板重载:

Parameter( string param_name, string param_description, bool dft ) { type_ = BOOL;}
// note, no trailing semicolon required for inline method definitions
template<typename T>
Parameter( string param_name, string param_description, T dft )
{ 
    type_ = NUMBER;
    value = static_cast<double>(dft);
}

(假定"真正的代码"实际上对dft做了一些事情)。

如果类型不能被赋值为double,则会得到编译错误。

其他答案使用这种技术的更高级的版本,允许您让T只匹配某些类型(与我的版本相反,它匹配所有类型,但如果使用无效类型,则会出现错误)。