Вопрос

C++11 added very useful container std::tuple, now I may convert many structures to std::tuple :

// my Field class
struct Field 
{
     std::string path;
     std::string name;
     int id;
     int parent_id;
     int remote_id;    
};

//create
Field field = {"C:/", "file.txt", 23, 20, 41 };  

 //usage
  foo( field.path );
  field.name= new_name;
  int id = field.id;

to

//to std::tuple,               /--path,  /--name      /--id, /--parend_id,   /--remote_id
using Field = std::tuple< std::string, std::string , int,   int ,           int >;

//create
auto field = make_tuple<Field>("C:\", "file.txt", 23, 20, 41);      



// usage
     foo( std::get<0>(field) );  // may easy forget that the 0-index is path
     std::get<1>(field) = new_name; // and  1-index is name
     int id = std::get<2>(field);   // and 2-index is id, also if I replace it to 3, 
                       //I give `parent_id` instead of `id`, but compiler nothing say about.

But, here is only one disadvantage for using std::tuple in big projects - may easy forget what was meaning of each type of tuple, because here isn't access by name, only by index.

For that reason, I would use old Field class.

My question is that, Can I solve this disadvantage simple and beatiful?

Это было полезно?

Решение

Yes, you can solve the disadvantage both simply and beautifully:

Use the right tool for the job! In this case, structs or classes.

Tuples are not meant to replaces structs in cases like this. Just because you have a new and shiny hammer in your toolbox does not mean that you should now use it to cut wood.

Другие советы

Well, conceptually tuple and plain old struct are very similiar. The main difference is that members of struct are accessed using a name, while members of tuple are accessed using an index.

So it seems you want to use tuple as a struct - why not just use struct?

You can use an enum to provide "field names":

enum FIELDS { path, name, id, parent_id, remote_id };
auto field = make_tuple<Field>("C:\", "file.txt", 23, 20, 41);      

foo( std::get<FIELDS::path>(field) );  // may easy forget that the 0-index is path
std::get<FIELDS::name>(field) = new_name; // and  1-index is name
int id = std::get<FIELDS::id>(field);  

(After edit, I'm using a qualified version for the enums here because they are rather common field names, but it's not strictly necessary)

In general, you should only use tuple for data that will be wrapped up and consumed within a few lines of each other, or when you actually have no knowledge of what the data is other than you need to package it together. Sometimes both.

This makes it very useful for generic programming where you want to, say, package up some arguments and unpack them later. Or, if you have a local lambda that you want to a sub-result out of and don't want to make a struct for it -- but even then, I'd be tempted with a struct.

A great use for tuple is to have your struct return a std::tie (a tuple of references) of its parameters via a make_tie method (and const version). tuple writes things like a lexical operator< for you, and this results in bug resistant implementations of < and == and even = in some cases (where default equality isn't quite right, but you want to invoke default equality as a sub-problem).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top