С++ 14 с использованием ключевого слова auto в определении метода

У меня есть несколько std::unordered_maps. Все они имеют std::string как свой ключ, и их данные различаются. Я хочу сделать строку csv из заданных ключей карты, потому что эти данные должны быть отправлены по проводу подключенному клиенту. На данный момент у меня есть метод для каждой отдельной карты. Я хотел сделать это родовым, и я придумал следующее:

std::string myClass::getCollection(auto& myMap) {
    std::vector <std::string> tmpVec;
    for ( auto& elem : myMap) {
        tmpVec.push_back(elem.first);
    }
    std::stringstream ss;
    for ( auto& elem : tmpVec ) {
        ss << elem <<',';
    }
    std::string result=ss.str();
    result.pop_back(); //remove the last ','
    return result;
}

Я компилирую с gcc 6.1.0 и -std = С++ 14 с использованием eclipse, и он компилируется, но он не связан. Компилятор жалуется на undefined ссылку на std::__cxx11::getCollection(someMap);

Независимо от данных карты и того, как я ее называю, она всегда говорит мне:

Invalid arguments ' Candidates are: std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> getCollection() '

Как это решить?

Ответ 1

Как и в С++ 14 auto параметры разрешены только в lambdas (в соответствии с комментарием @ildjarn), вы можете просто разработать шаблон функции, шаблонный по типу карты, например:

#include <sstream>
#include <string>
#include <vector>

class myClass {
...

template <typename MapType>
std::string getCollection(const MapType& myMap) {
    std::vector <std::string> tmpVec;
    for ( const auto& elem : myMap) {
        tmpVec.push_back(elem.first);
    }
    std::stringstream ss;
    for ( const auto& elem : tmpVec ) {
        ss << elem <<',';
    }
    std::string result=ss.str();
    result.pop_back(); //remove the last ','
    return result;
}

Заметим также добавление const для некоторой const-корректности.

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

И поскольку вы просто заинтересованы в использовании потока строк в качестве выходного потока, лучше использовать ostringstream вместо stringstream, поскольку он более эффективен и лучше передает ваши намерения.

#include <sstream>  // for std::ostringstream
#include <string>   // for std::string
...

template <typename MapType>
std::string getCollection(const MapType& myMap) {
    std::ostringstream ss;
    for (const auto& elem : myMap) {
        ss << elem.first << ',';
    }
    std::string result = ss.str();
    result.pop_back(); // remove the last ','
    return result;
}

Ответ 2

Почему бы просто не использовать шаблон?

template <typename TMap>
std::string myClass::GetCollection(TMap &myMap) {
    std::vector <std::string> tmpVec;
    for ( auto& elem : myMap) {
        tmpVec.push_back(elem.first);
    }
    std::stringstream ss;
    for ( auto& elem : tmpVec ) {
        ss << elem <<',';
    }
    std::string result=ss.str();
    result.pop_back(); //remove the last ','
    return result;
}

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

Ответ 3

auto параметры разрешены только в lambdas в С++ 14.

Вероятно, это потому, что в классической функции, такой как ваша, вы могли бы объявить шаблон функции (что в основном происходит в случае лямбда), в то время как lambdas не может быть шаблонами.