C++14 using auto keyword in a method's definition [duplicate]
Asked Answered
S

3

12

I have several std::unordered_maps. They all have an std::string as their key and their data differs. I want to make a csv string from a given map's keys because that data needs to be sent over the wire to a connected client. At the moment I have a method for each individual map. I wanted to make this generic and I came up with the following :

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

I compile with gcc 6.1.0 and -std=c++14 using eclipse and it compiles but it doesn't link. The linker complains about undefined reference to std::__cxx11::getCollection(someMap);

Regardless of the map data and the way I call it, it always tells me :

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

How do I solve this?

Sharpen answered 7/10, 2016 at 10:52 Comment(7)
std::string myClass::getCollection(auto& myMap) is not valid syntax. Specifically, auto is not a valid parameter type for a member function.Dekker
is what I'm trying to accomplish possible using another approach then? I thought it was possible to use auto as a parameter in c++14... apparently I'm wrong then...Sharpen
"I thought it was possible to use auto as a parameter in c++14..." Only for lambdas. "is what I'm trying to accomplish possible using another approach then?" Yes, just use normal templates: template<typename MapT> std::string myClass::getCollection(MapT& myMap)Dekker
Using auto in function parameters is currently non-standard, but might get into the language in C++20. It's called an "abbreviated function template" and I think it's part of the Concepts proposal. GCC provides it as an extension currently; if you compile with -pedantic it'll fail.Legume
Since 'auto' parameter is just like a template param, you should define (not just declare) the member function in the header file - otherwise the definition won't get instantiated in some translation units.Parricide
Missing a minimal reproducible example for the link error...Naxos
@Marc Glisse - I'll make one and add it to the questionSharpen
S
15

As in C++14 auto parameters are only allowed in lambdas (as per @ildjarn's comment), you can just develop a function template, templateized on the map type, e.g.:

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

Note also the addition of const for some const-correctness.

Moreover, why not just building the output string directly using the string stream object, without populating an intermediate vector<string> (which is more code, more potential for bugs, more overhead, less efficiency)?

And, since you are just interested in using the string stream as an output stream, using ostringstream instead of stringstream is better as it's more efficient and communicates your intent better.

#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;
}
Scalable answered 7/10, 2016 at 11:1 Comment(5)
Thank you for your improvements. I keep having the same linking problems... undefined reference to `std::__cxx11::Sharpen
Do you have the template method implemented inline in some header, or at least accessible by your client's code? Do you include all the required headers (e.g. <sstream>, <vector>, <string>, your map collection's headers)?Scalable
yes, I have template <typename MapType> std::string getCollection(MapType& myMap); in my header file that is included in the cpp where the template/function is and also included in another header where the class's method gets calledSharpen
@ZoOl007: The function template must be implemented inline in a header file if you want to call it in another header or .cpp file. It's not like for ordinary non-templated functions, that you can declare in a header and implement in a separate .cpp file.Scalable
ok, it works now... this is new for me... so, all templated functions are best put completely in a header file then? Confusing difference. Thank you very much for your time!Sharpen
B
7

Why not just use a template?

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

Your method is exactly the same, but instead of the auto keyword, we use template function syntax to handle the type inference.

Backflow answered 7/10, 2016 at 11:0 Comment(3)
Maybe mention that auto cannot be used as parameter type to a function?Tory
Thank you. I'm still having the same undefined reference to `std::__cxx11::Sharpen
@Sharpen : That is a namespace, so you must be leaving something off the end. The important part in this case... ;-]Dekker
G
6

auto parameters are only allowed in lambdas in C++14.

Probably this is since in an classic function like yours you could have declared a function template (which is basically what happens in the lambda case) while lambdas can't be templates.

Grandpapa answered 7/10, 2016 at 11:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.