Шаблон C ++ в сочетании с типами возврата STL - PullRequest
2 голосов
/ 06 декабря 2011

У меня есть шаблонный класс

template <typename T>
class Factors
{
    public:
    Factors(){};
    deque<string> stringsDeck;

    // some methods and variables here
   map <string, string> getNext();
};

Метод getNext объединяет строку, используемую в качестве ключа, со строками из stringsDeck, используемыми в качестве значения, и возвращает map <string,string>. При условии, что у меня есть шаблонизированные функции stringify и string2num, я хотел бы иметь метод map<string,Scalar> getNext(), который для любого другого типа, кроме строковых, преобразует значения карты в указанный тип шаблона T.

Компилятор не позволяет мне перегружать два метода с одинаковым именем, но с разным типом возвращаемого значения, а именно:

map <string, T > getNext()
{
// converts the values of getNext() return map into the specified type T
return convertedMapWithValuesOfTypeT;
}

Каким может быть решение в этом случае? Я хотел бы сохранить имя метода одинаковым для строковых и других типов (в основном числовые типы, которые можно преобразовать из строки с помощью лексического приведения)

Ответы [ 2 ]

4 голосов
/ 06 декабря 2011

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

  • Самое простое (и, следовательно, предпочтительное решение в большинстве случаев) - просто дать двум функциям разные имена: getNextAsMapToType и getNextAsMapToString,например.
  • В качестве альтернативы, вы можете объявить функцию шаблоном:
    template<typename U>
    std::map<string, U> getNext();
    
    затем специализировать эту функцию для std::string и T (и ни для чего другого).Пользователь должен будет указать getNext<std::string>() или getNext<<i>...</i>> для вызова того, который ему нужен.Как правило, я считаю, что это значительно менее читабельно, чем предыдущее решение, но оно может быть применимо в шаблонах, где имена должны содержать или, по крайней мере, предлагать имя типа.
  • Наконец, можно симулировать перегрузку возвращаемого типа, если вы не возражаете против некоторой дополнительной сложности.Для этого вам все равно нужно реализовать одно из других решений, но клиентский код его не видит.По сути, ваша getNext() функция должна возвращать прокси с перегруженными функциями преобразования, что-то вроде:
    class Proxy
    {
        Factors* myOwner;
    public:
        Proxy( Factors& owner ) : myOwner( &owner ) {}
        operator std::map<std::string, std::string>() const
        {
            return myOwner->getNextAsMapToString();
        }
        operator std::map<std::string, T>() const
        {
            return myOwner->getNextAsMapToType();
        }
    };
    
    Proxy getNext() { return Proxy( *this ); }
    
    Клиентский код может просто вызывать getNext(), и в зависимости от того, что они делают с результатами, getNextAsMapToString или getNextAsMapToType будет называться.
0 голосов
/ 06 декабря 2011

Вы можете добавить проверку выполнения в getNext, используя [typeid] (http://en.cppreference.com/w/cpp/language/typeid), чтобы увидеть, является ли T строкой или нет.

Что-то вроде:

template <typename T>
class Factors
{
    public:
    Factors(){};
    deque<string> stringsDeck;

    // some methods and variables here
    map <string, T> getNext();
    {
        if (typeid(T) == typeid(string))
        {
            // Special handling for strings
        }
        else
        {
            // Do something else for other types
        }
    }
};

Edit

Как подсказывает fschoenm, специализация шаблонов, вероятно, лучше:

template <typename T>
class Factors
{
    public:
    Factors(){};

    // some methods and variables here
    map <string, T> getNext();
};


template <>
class Factors<string>
{
    public:
    Factors(){};
    deque<string> stringsDeck;

    // some methods and variables here
    map <string, string> getNext();
};
...