Перегрузка типа возвращаемого значения функции C ++ в контейнере карты функций: автоматический вывод завершается ошибкой компилятора - PullRequest
0 голосов
/ 15 декабря 2011

У меня есть простой класс, такой как this (который ведет себя как Boost :: overload, но в нем есть именованные функции (я использую его для упрощенного \ минимизированного отражения \ интроспекции)). У него проблемы с несколькими типами возвращаемых значений для входных аргументов (ошибка компилятора 3066). Мой код:

#include <iostream>
#include <string>
#include <map>
#include <vector>

template < class T0, class T1 >
class my_map {
    typedef T0 type_0;
    typedef T1 type_1;
    std::map < std::string, type_0 * >T0_var;
    std::map < std::string, type_1 * >T1_var;
    friend class apitemp;
public:
    my_map(int meaningless0 = 42, int meaningless1 = 42) {} 
    class apitemp {
        std::string n_;
        my_map *p;
    public: 
        apitemp(std::string name_, my_map * parent):n_(name_), p(parent) {}
        operator  type_0 *() {
            return p->T0_var[n_];
        }
        operator  type_1 *() {
            return p->T1_var[n_];
        }
    };
    void insert(std::string name, type_0 * ptr) {
       T0_var[name] = ptr;
    }
    void insert(std::string name, type_1 * ptr) {
       T1_var[name] = ptr;
    }
    apitemp operator[] (std::string n_) {
       return apitemp(n_, this);
    }
};

template<class out, class in1, class in2>
    out hello_world(in1 name, in2 number )
{
    name += "!";
    std::cout << "Hello, " << name << std::endl;
    return number;
}

template<class in1, class in2>
std::string hello_world(in1 name, in2 number )
{
    name += "!";
    std::cout << "Hello, " << name << std::endl;
    return std::string("Yep, we can!");
}

int main() {
    int a =  hello_world<int, std::string, const int &>("Tim", 25);
    std::string b = hello_world<std::string, const int &>("Tim", 25);

    my_map<int(std::string, const int &), std::string(std::string, const int &)> myMap;
    myMap.insert("my_method_hello", &hello_world<int, std::string, const int &> ); 
    myMap.insert("my_method_hello2", &hello_world<std::string, const int &> ); 
    //int a = myMap["my_method_hello"]("Tim", 25); // error C3066: there are multiple ways that an object of this type can be called with these arguments
    //std::string b = myMap["my_method_hello2"]("Tim", 25); // // error C3066: there are multiple ways that an object of this type can be called with these arguments

    std::cin.get();
}

Как представить в своем API несколько функций возвращаемого типа? Возможно ли это в невидимом для API пользовательском пути? Или, по крайней мере, с чем-то, что беспокоит пользователя API, например

int a = myMap["my_method_hello"]("Tim", 25)::int; 
std::string b = myMap["my_method_hello2"]("Tim", 25)::string;

1 Ответ

3 голосов
/ 15 декабря 2011

Один из способов сделать это - заставить myMap["my_method_hello"]("Tim", 25) вернуть прокси-объект, который определяет operator int(), operator std::string() и т. Д. Для каждого типа, который вы хотите вернуть. Другой способ - заставить прокси-объект определять явные .asInt(), .asString() методы для каждого типа.

Техника перегруженного оператора может сбить с толку, если целевой тип не указан явно в исходном коде (например, если вы передаете результат в функцию). Точно так же тип прокси может запутать шаблонные функции, которым вы его передаете, и не сможет легко выбрать перегруженную функцию, если набор кандидатов включает функции, принимающие как int, так и std::string (или другие типы прокси-авто -конвертирует в. Поэтому я рекомендую предоставлять функции .asInt() и т. д. в дополнение к любым операторам.

Вы также можете произносить функции .asInt() и т. Д., Например template<typename T> as(), и использовать явную специализацию для определения новых преобразований. Единственным недостатком этого является то, что исходный код становится немного сложнее для чтения.

...