2014-10-23 3 views
3

Я видел варианты этого вопроса, но обычно они включают функции, возвращающие один и тот же тип. Вот мой код:Сопоставление строк с функциями с разными типами возврата

#include <iostream> 
#include <functional> 
#include <map> 

using namespace std; 

void checkType(int x){ 
    cout << "we got an int: " << x << endl; 
} 

void checkType(float x){ 
    cout << "we got a float: " << x << endl; 
} 

int getInt(){ 
    return 1; 
} 

float getFloat(){ 
    return -101.23f; 
} 

int main(){ 
    map<string, function<float()> > myMap({ 
     {"int", getInt}, 
     {"float", getFloat} 
    }); 

    checkType(myMap["int"]()); 
    checkType(myMap["float"]()); 

    return 1; 
} 

Цель здесь назвать различные версии перегруженной функции (CheckType), в зависимости от того, что отображенной функции возвращает. Очевидно, что функция checkType (float) получает вызов дважды, потому что моя карта думает, что все ее функции возвращают float.

Есть ли хороший способ сделать это? И это вообще хорошая практика? Я нашел другое решение, но я думаю, что если что-то вроде этого законно, это может быть довольно сексуально.

+3

Рассмотрим: 'струны S = "Int"; checkType (myMap [s]()); 'Вы хотите, чтобы это вызывало' checkType (int) '? Я не вижу, как это может сработать. Какая перегрузка для вызова определяется полностью во время компиляции - она ​​не может измениться во время выполнения в зависимости от значения, которое имеет строковая переменная. –

+0

Eh функция float не должна вызываться дважды. Вы должны получить сбой компиляции. –

+0

@LightnessRacesinOrbit Даже если тип возврата не является частью подписи функции? –

ответ

2

Как вы уже узнали, способ, которым вы его реализовали, не будет работать, поскольку функции, хранящиеся на карте, возвращают float.

Правильный способ - использовать стирание стилей, но если вы используете void *, вам необходимо позаботиться о правильном литье. Другой вариант - использовать boost::any, или QVariant.

В этом примере используется const void* для удаления типов:

#include <iostream> 
#include <functional> 
#include <map> 

using namespace std; 

void callForInt(const void* x){ 
    const int* realX = static_cast < const int* >(x); 
    cout << "we got an int: " << *realX << endl; 
} 

void callForFloat(const void* x){ 
    const float* realX = static_cast < const float* >(x); 
    cout << "we got a float: " << *realX << endl; 
} 

int main(){ 
    map<string, function<void(const void*)> > myMap({ 
     {"int", callForInt}, 
     {"float", callForFloat} 
    }); 

    const int v1 = 1; 
    const float v2 = -101.23f; 

    myMap["int"](&v1); 
    myMap["float"](&v2); 
} 
+0

Достаточно справедливо, спасибо за ответ. Мое решение было чем-то похоже ... хотя я немного нуб в этом. Я попытался использовать typeid (чтобы проверить, какой тип отправляется), а также динамический приведение, чтобы проверить, какой указатель возвращает действительный ... если это имеет смысл. В любом случае, цель состояла в том, чтобы отображенные функции принимали один и тот же набор параметров, но возвращали разные вещи. Поскольку отображаемая функция всегда возвращает void, это меня действительно не удовлетворяет, но я понимаю проблему и соглашусь с вашим ответом. – user1973454

+0

@ user1973454 С 'boost :: any' и' QVariant' вы можете получить некоторую безопасность типов (если вы используете их броски, а не reinterpret_cast или c-style casting) –