How to shorten this method signature? - c++

I have the following class with a method signature as below:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
In the implementation file, I've got this:
std::vector<std::string> Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
So I thought to myself, let's see if I can simplify this function signature a bit with some auto-magic as it's getting to be a "bit of a line-full"! So I tried this...
class Foo
{
public:
auto barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
auto Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Now ignoring the fact that, yes I can use a "using namespace std", to trim it down a lot, I was wondering why the compiler gave me an error "a function that returns 'auto' cannot be used before it is defined".
I personally would have thought the compiler would have easily been able to deduce the return type of the method, but in this case it doesn't seem so. Sure, you can fix it with a trailing return type as below:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&) -> std::vector<std::string>;
}
But then if you use the above, it's no better than it was before. So, apart from "using namespace std", is there a nicer way to do the above, and why can't the compiler deduce the return-type in this instance? Or even, does it depend on how this method is invoked that's causing the compiler not to be able to figure out the return type.

The issue here is an issue of how include files work. Your error:
a function that returns 'auto' cannot be used before it is defined
means that in the file you are using your function, its definition (ie. implementation) not anywhere in the file before the usage. This means that the compiler compiling your code using the function can't deduce the functions return type, as that requires access to the definition (implementation). The most likely reason for this is that the function's definition (implementation) is in its own source (.cpp, .c, etc.) file, that is not included. To more fully understand this, I recommend reading this answer, and perhaps this answer as well.
To address the titular question, likely the easiest way to shorten that signature is with a typedef. More specifically, you can add the following code wherever you see appropriate, provided the scoping is appropriate (I would add it as a public member in your class):
typedef std::vector<std::string> strvec;
This allows you to re-write your method signature as the much more manageable:
strvec barreuslts(const strvec&, const strvec&)

When sticking to C++11, you can't rely on deduced return types, you need the trailing return type (C++14 allows that, though). As there is nothing special about the trailing return type in your case, i.e., no expression is passed decltype to determine the return type, I would instead try to shorten the method signature with some type aliases:
class Foo
{
public:
using StrVec = std::vector<std::string>;
StrVec barResults(const StrVec&, const StrVec&);
};
Foo::StrVec Foo::barResults(const StrVec& list1, const StrVec& list2)
{
StrVec results;
// small amount of implementation here...
return results;
}

If you are just looking for a visually appealing way to deal with longer signatures, stop forcing everything to be on one line. Be liberal with your vertical spacing and insert line breaks. The signature contains quality information for the caller and what you may be looking for is a multi-line signature. If you are working with 80 character page widths, reconsider the indentation on the access specifier.
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&,
const std::vector<std::string>&);
}
std::vector<std::string>
Foo::barResults(const std::vector<std::string>& list1,
const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
There are many styles when it comes to splitting up a declaration. Having a tool like clang-format in your toolset will do this automatically and consistently for you.

Related

Standard way to handle the encapsulated access to values stored in private map without breaking the abstraction in C++

I want to create a class in order to manage markup language (such as HTML) in C++. I would like my class to retain attributes and sub-tags. The problem is, given encapsulated containers, how to properly abstract the accesses and what to return in order to provide an easy way to check if the value returned is valid.
I defined my class containing two maps as private members (nominally, std::map<std::string, Tag> _children; and std::map<std::string, std::string> _attr;. I defined two functions to populate these fields and I would like to define two functions to read-access the stored elements.
The problem is, I don't want to break my abstraction and, as I'm doing this in order to work on my c++ skills, I would like to find the proper way (or cleaner way, or standard way) to do it.
One basic solution would be to simply call return map.find(s);, but then I would have to define the return type of my function as std::map<std::string, Tag>::const_iterator, which would break the abstraction. So I could dereference the iterator returned by map.find(), but in case the value in not in the map I would dereference a non-dereferencable iterator (_children.cend()).
What I defined so far:
using namespace std;
class Tag {
static const regex re_get_name, re_get_attributes;
string _name;
map<string,string> _attr;
map<string,Tag> _children;
public:
Tag(const string &toParse) {
/* Parse line using the regex */
}
const string& name() const {
return _name;
}
Tag& add_child(const Tag& child) {
_children.insert(child._name, child);
return *this;
}
SOMETHING get_child(const string& name) const {
map<string,Tag>::const_iterator val = _children.find(name);
/* Do something here, but what ? */
return something;
}
SOMETHING attr(const string& name) const {
map<string, string>::const_iterator val = _attr.find(name);
/* Do something here, but what ? */
return something;
}
};
const regex Tag::re_get_name("^<([^\\s]+)");
const regex Tag::re_get_attributes(" ([^\\s]+) = \"([^\\s]+)\"");
What would be the proper way to handle this kind on situation in C++? Should I create my own Tag::const_iterator type? If so, how to? Should I go for a more "C" approach, where I just define the return type as Tag& and return NULL if the map doesn't contain my key? Should I be more OOP with a static member static const Tag NOT_FOUND, and return a reference to this object if the element isn't in my map? I also thought of throwing an exception, but exception management seems to be quite heavy and ineffective in C++.
std::optional could help you, but needs a C++17 ready standard library, so in the meantime you could also use boost::optional which is more or less the same, since AFAIK std::optionals design was based on the boost one. (As boost is often the source for new C++ standard proposals)
Even as I am reluctant to make you a proposal because of the general problem of your approach, I still wrote one for you, but please consider the points after the code:
#include <string>
#include <regex>
#include <map>
#include <boost/optional.hpp>
class Tag {
static const std::regex re_get_name, re_get_attributes;
using string = std::string;
string _name;
std::map<string,string> _attr;
std::map<string,Tag> _children;
public:
Tag(const string &toParse) {
/* Parse line using the regex */
}
const string& name() const {
return _name;
}
Tag& add_child(const Tag& child) {
_children.emplace(child._name, child);
return *this;
}
boost::optional<Tag> get_child(const string& name) const {
auto val = _children.find(name);
return val == _children.cend() ? boost::optional<Tag>{} : boost::optional<Tag>{val->second};
}
boost::optional<string> attr(const string& name) const {
auto val = _attr.find(name);
return val == _attr.cend() ? boost::optional<string>{} : boost::optional<string>{val->second};
}
};
As you can see you are basically just reimplementing container semantics of std::map but also with the somehow built in parser logic. I strongly disagree from this approach, since parsing gets ugly very fast in a hurry, and mixing value generation code into a container which could i.e. should be use as a value class will make things even worse.
My first suggestion is to just declare/use your Tag class/struct as a value class, so just containing the std::maps as public members. Put your parsing functions in a namespace along with the Tag container, and let them just be functions or distinct classes if needed.
My second suggestion is small one: Don't prefix with _, it's reserved and considered bad style, but you can use it as a suffix. Also don't use using namespace directives outside of a class/function/namespace block i.e. global, it's bad style in a .cpp, and extremely bad style in a header /.h/.hpp
My third suggestion: Use the boost spirit qi parser frame work, you would just declare your value classes as I suggestion first, while qi would automatically fill them, via boost fusion. If you know the EBNF notation already, you can just write the EBNF like grammar in C++, and the compiler will generate a parser via template magic. However qi and especially fusion has some issues, but it makes things much easier in the long run. Regexes only does half of the parsing logic, at best.

Using alias from header file in corresponding source file

I just started learning more of c++ and am writing a small rendering engine as an example case study. As i started to implement more code I got annoyed by typing types like
std::vector<std::vector<int>>
over and over again. As most of you know already, this get's infinitely worse if you are looping over said vector
for (std::vector<std::vector<Tile>>::const_iterator layerRow = ...) {}
Since this is not just annoying but also very error prone, I looked into using typedefs and soon changed those into alias', following Scott Meyers advice in "More effective C++".
I got one problem now which I can't seem to wrap my head around. Given the following two files (corresponding header and source file):
map.h:
class Map
{
public:
using tileLayerVector_t = std::vector<std::vector<Tile>>;
using rawDataLayerVector_t = std::vector<std::vector<int>>;
tileLayerVector_t getTileLayer(const std::string pLayerName) const;
void generateTileMapLayer(const std::string pMapLayerName, const rawDataLayerVector_t pRawMapData, const std::shared_ptr<Texture> pTexture);
}
map.cpp:
#include <map.h>
tileLayerVector_t Map::getTileLayer(const std::string pLayerName) const
{
return mapLayers.at(pLayerName);
}
void Map::generateTileMapLayer(const std::string pMapLayerName, const
rawDataLayerVector_t pRawMapData, const std::shared_ptr<Texture> pTexture)
{
int tileCount = 0;
int xPos = 0;
int yPos = 0;
...
std::pair<std::string, tileLayerVector_t> tileLayer(pMapLayerName, tileMapLayer);
mapLayers.insert(tileLayer);
}
Function generateTileMapLayer() compiles fine without a problem. As soon as I implement getTileLayer() the UI is giving me an error "identifier 'tileLayerVector_t' is undefined" and the compiler is giving me some weird error about a missing ";" somewhere. This compiler error vanishes if I put getTileLayer() in comments.
I don't understand why I can use the alias within the function generateTileMapLayer() as a type definition for the hash map, but cannot use it as a return type for getTileLayer(). I put Map::tileLayerVector_t as a return type and it works. Why does it work without the namespace within generateTileMapLayer() though?
Maybe someone can help me with this. Thank you in advance!
A class defines a scope. How you access something in a given scope depends on whether you are writing code that's inside or outside that scope.
So when you make the declaration using tileLayerVector_t = ...; within class Map you are providing an alias for a new type Map::tileLayerVector.
This is why your code inside the class can use the type without qualification, but code outside cannot.
You could move your using-declarations outside the class, but that would pollute the global namespace. A better solution, I think, would be to simply qualify the types where needed:
Map::tileLayerVector_t Map::getTileLayer(...) // must qualify type here
{
tileLayerVector_t temp = ...; // inside a class method, no problem here
}
A more modern solution would be to use "type inference". I believe you need at least a C++11 compliant compiler to take advantage of this feature. My understanding is that the trailing return type allows the compiler to defer establishing the actual type until after the function signature has been generated, at which point the scope has been established.
auto Map::getTileLayer(...) -> tileLayerVector_t
{
....
}

boost::program_options validation per argument instead of per argument type?

boost::program_options appears to support some level of custom validation but it seems odd to me that the validation is written in terms of types, and not per-argument, and I'm wondering if I'm missing something here.
For example, say you have a "file editing" program that takes input and output filenames from the command line. Next assume that you want to store these into variables of type boost::filesystem::path. Now, let's say we have a requirement that the input file must exist, but the output file doesn't (i.e. if the output file doesn't exist, we'll create it.) Ideally, we'd have a way to test that the input argument exists, and separately that the output file either exists and is writable or is in a directory that we can write to. (The specific differences here aren't actually relevant. This applies to any situation where you're using the same type in multiple places where you'd like to have different validation rules depending on the use.)
Because we configure validators by creating overrides of validate (which are presumably found at compile time by their type signatures, it appears we can only have one validator for all instances of boost::filesystem::path. I've seen the notify hook, but the signature of those callbacks has a const qualifier, so it doesn't seem like you could modify the value, and it's not clear in the documentation how throwing in a notify callback would get worked in to the validation system.
This seems like a pretty fundamental limitation to the point where I think I'm probably missing something. Am I? Thoughts?
It never hurts to have one type per concept in a program. If the two paths represent different concepts, give them their own types:
#include <iostream>
#include <cstdlib>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
namespace po = boost::program_options;
namespace fs = boost::filesystem;
template<class Type, class Tag>
struct tagged
{
Type const& get() const { return value_; }
Type& get() { return value_; }
operator Type& () { get(); }
friend decltype(auto) operator>>(std::istream& is, tagged& t) {
return is >> t.get();
}
friend decltype(auto) operator<<(std::ostream& os, tagged const& t) {
return os << t.get();
}
// and so on...
Type value_;
};
using bar_path = tagged<fs::path, class bar_path_tag>;
using foo_path = tagged<fs::path, class foo_path_tag>;
int main()
{
bar_path bar;
foo_path foo;
po::options_description desc("prog");
desc.add_options()
("foo", po::value(&foo), "a foo path")
("bar", po::value(&bar), "a bar path")
;
}
You can put per-option validation logic into a notifier callback.

boost::interprocess::basic_string as std::string

I am trying to replace a class method which returns const std::string & with const boost::interprocess::basic_string &. The main challenge I am facing is the incompatibility between the two classes despite their implementation similarity. For more clear explanation I will put that into code
class A
{ std::string m_str;
const std::string & StrVal() { return m_str; }
}
Now this class has to look like this:
typedef boost::interprocess::allocator<char,boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocatorChar;
typedef boost::interprocess::basic_string<char, std::char_traits<char>,ShmemAllocatorChar> ShMemString;
class A
{
ShMemString m_str;
const ShMemString & StrVal() { return m_str; }
}
The problem is that we have a huge code base depending on this:
A a;
const std::string & str = a.StrVal();
// Many string specific operations go here, comparing str with other std::strings for instance
Even If I go over all the code replacing the expected results with const ShMemString &, it will be an even harder work to also fix the uses that follow. I was surprised to find out that the boost's string does not include any comparison/construction methods from std::string.
Any ideas on how to approach this?
Even if boost::interprocess::basic_string<> did have a conversion to std::basic_string<>, it would be completely useless for your purposes -- after the conversion, the interprocess string would be destroyed, and its allocator is the important one (i.e., the one holding the data in shared memory, which I assume is your motivation for switching basic_string<> implementations in the first place).
So, in the end, you have no choice but to go over all the code replacing the expected results with ShMemString const& (or auto const& if your compiler is recent enough to support it).
To make this less painful in the future, typedef judiciously:
struct A
{
typedef ShMemString StrValType;
StrValType const& StrVal() { return m_str; }
private:
StrValType m_str;
};
// ...
A a;
A::StrValType const& str = a.StrVal();
This way, only the typedef inside of A needs to change and all code relying on it will automatically use the correct type.
The problem is that we have a huge code base depending on this:
Why does A::StrVal in the second one return an interprocess::basic_string? It is an implementation detail of the class A that it uses interprocess::basic_string internally. The actual string class it's interface uses does not have to be the same. This is simply poor refactoring.
A::StrVal should return a std::string, just like always (well, not a const& of course, but user code won't need to change because of that). And therefore, A::StrVal will need to do the conversion between the two string types. That's how proper refactoring is done: you change the implementation, but the interface stays the same.
Yes, this means you're going to have to copy the string data. Live with it.

Populate a static member container in c++

I've got a static class member which is some container, like
(Foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
I need to populate the list with a number of specific values. Actually it should be also const, but that might overcomplicate the problem further.
All the class member functions are static, so initializing it in a constructor doesn't make sense.
a common solution is to do something like this:
// header
class Foo
{
...
private:
static list<string> s_List;
}
// cpp
list<string> init()
{
list<string> tmp;
... fill tmp with strings
return tmp;
}
list<string> Foo::s_List(init());
the other method is like Neil Butterworth suggested.
Another alternative is to create a simple initialiser class:
list <string> Foo::s_List;
struct Init {
Init() {
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
}
};
static Init doInit;
Note that, as the list is private, this will probably require you to make Init a friend of Foo. It's also often convenient to make such classes be contained by the class they are initialising.
However, I just re-read your question and another thought occurs - if the list is const, you will presumably not be changing it, in which case a simple array of strings, initialised with the strings in sorted order may be a better solution. It will certainly be faster to search (using std::binary_search) than a list, and can of course be easily initialised.
If your compiler supports C++0x, this is actually trivial to accomplish.
#include <iostream>
#include <list>
class Foo
{
public:
static std::list<std::string> s_List;
};
std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"};
int main()
{
for(const std::string& str : Foo::s_List)
std::cout << str << std::endl;
return 0;
}
This works for both const and non-const static members. I've tested this snippet with clang-4.2, gcc-4.7, gcc-4.6, and gcc-4.5. Gcc-4.5 does not support the updated for syntax, so you'd have to use a traditional for loop with iterators. Also, don't forget to pass the -std=c++0x flag to the compiler. I'm reasonably confident Visual Studio supports this as well, but I don't know for sure and don't know which versions.
It depends on what values you need to put in that list. Are they static or do they require some form of computation?
If they are static, you can do this:
namespace {
const char* const initVals[] = { "A", "B", "C" };
}
list<string> Foo::s_list(initVals, initVals + 3);
one possible solution would be to use an accessor method that checks to see if it is initialized, and does so if it isn't.
The ways I(the author of the question) have vainly tried to do this.
I tried to do smth like (in Foo.cpp):
list<string> Foo::s_List = list<string>();
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
But that gives a compiler error.
Then I thought of making an Initialize() method and calling it right from the code
void Foo::Initialize()
{
s_List.insert("rats");
s_List.insert("cats");
}
Foo::Initialize();
// error: compiler considers it to be a redefenition of the method, not a call.
The only viable idea left (havent yet tried) would be to check if the list is empty in each method that uses it, and if it's the case, call Initialize(). But that's ugly!