Неоднозначный вызов: int to double или bool

У меня есть класс Parameter, и я перегрузил конструктор, чтобы он принимал логические или двойные значения. Когда вы даете ему int, он не может построить:

ошибка C2668: 'Parameter::Parameter': неоднозначный вызов перегруженной функции может быть 'Parameter::Parameter(std::string,std::string,double)' или
'Parameter::Parameter(std::string ,std::string,bool)'

Я считаю, что у меня есть два варианта:

  1. Перегрузка с int по умолчанию
  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
}

person user1582665    schedule 12.08.2014    source источник


Ответы (3)


Если вы хотите удалить ctor с конечным элементом bool из рассмотрения, если это не явный элемент 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_t и decay_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;}
person Deduplicator    schedule 12.08.2014
comment
enable_if_t<is_same<decay_t<X>, bool>::value> = 0 - не хватает *? - person T.C.; 13.08.2014
comment
@T.C.: Вы говорите, что и CLANG, и G++ нужны там? - person Deduplicator; 13.08.2014
comment
Я говорю, что замена никогда не будет успешной, как написано, потому что вы не можете параметр типа void. - person T.C.; 13.08.2014
comment
@T.C.: Надо было поэкспериментировать немного дольше, после того, как это, казалось, сработало. Теперь это так. - person Deduplicator; 13.08.2014
comment
Не удалось скомпилировать это на VS2010 16.00.40219.01 или gcc версии 4.4.6. Кажется, это, по крайней мере, несколько проблема версии, поскольку enable_if_t является типом С++ 14. Я работаю над разбором того, как это работает, чтобы решить мою собственную проблему. - person user1582665; 14.08.2014
comment
@ user1582665: добавлены примеры без decay_t и eable_if_t. - person Deduplicator; 14.08.2014

Вы можете реализовать это, используя шаблоны признаков для правильного приведения к удвоению.

#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
}

Это идеально подходит для вашего сценария: У меня есть масса параметров, и некоторые из них имеют тип unsigned long, float и т. д. очень просто добавить дополнительные черты (реализации DFTtrait), чтобы они соответствовали всем вашим потребностям. , например, если вы добавите:

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

ваш код будет автоматически поддерживать long long int и выполнять правильное приведение к double.

person Raydel Miranda    schedule 12.08.2014

Очень простой версией было бы использование параметра шаблона для конструктора с перегрузкой без шаблона для 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 соответствовать только определенным типам (в отличие от моей версии, где она соответствует каждому типу, но затем вы получаете сообщение об ошибке, если используются недопустимые типы).

person M.M    schedule 13.08.2014