set<int, char, bool> s(1, 'x', true);
assert(at_key<char>(s) == 'x');
typedef map<
pair<int, char>
, pair<double, std::string> >
map_type;
map_type m(
make_pair<int>('X')
, make_pair<double>("Men"));
std::cout << at_key<int>(m) << std::endl;
std::cout << at_key<double>(m) << std::endl;
--
---
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/N-kIXNrkTUk/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
typedef map<
pair<struct jonesy, int>
, pair<struct bonesy, int> >
map_type;
map_type m;
auto i1 = at_key<jonesy>(m);
auto i2 = at_key<bonesy>(m);
I just don't see how this would be more useful or easy to use than:
struct
{
int foo;
string bar;
} t = { 5, "hello" };
auto n = t.foo;
auto m = t.bar;
std::map<std::string, any> mp {{"string", "1"}, {"int", 1}, {"bool", true}, {"float", 1.5f}, {"char", 'c'}, {"long", 999}};
--
---
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/N-kIXNrkTUk/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
Imagine a C++ for all, not only for nerd people.
std::tuple<bool, int, std::string> f()Imagine that you are writing a library like this:public:
class MyLib
{
{// some cool computationreturn std::make_tuple(true, 0, "All works fine");}
std::tuple<bool, int, int> g() { .... }
};All method return some kind of tuple: the first member is a bool, the second is always an int (errorcode) the third depend by function. The user must remember that in case of g function the errorcode is the 2th not 3th.
template<typename t>
struct ErrorRet
{
bool didError;
int errorCode;
T actualData;
};
ErrorRet<int> g();
So If I have the possibility to "tag" a position of element in a tuple I can do something like that
class MyLib
{
public:
std::tuple<"result"@bool, "errorcode"@int, std::string> f()
{// some cool computationreturn std::make_tuple(true, 0, "All works fine");
}
std::tuple<"result"@bool, "errorcode"@int, int> g() { .... }
};than the user can do :MyLib lib;auto t = lib.g();std::cout << std::get<"errorcode">(t) << std::endl;In this way I create only the class that I needed without introduced any support struct or class. The code is more clear to read and to write!
To my mind, the only reason to use a tuple instead of a struct is because you want to compile-time iterate over the elements of the data structure. Which you can only do with a tuple, because C++ lacks reflection. Of course, what that means is that, once we do get compile-time reflection, the main use-case for tuple disappears.
typedef std::tuple<int, int, std::string> user_record_type; // Note that this definition is here for the example only. In my case, the type user_record_type will in fact be computed as a std::tuple<int, int, std::string> using metaprogramming.
user_record_type get_random_user_from_db();
//...
struct user { int id; int gid; std::string name; }
//...
user& u = (user)get_random_user_from_db();
std::cout << "User Id: " << u.id << " Group Id: " << u.gid << " User Name:" << u.name;
// a simple type-inferred tuple binding:
auto x = (0, 0.0f, "foo"); // the type of x is inferred to be the tuple type: (int, float, const char*)
// the same as above but without local type inference:
(int, float, const char*) x = (0, 0.0f, "foo");
// some tuple pattern binding expressions (with type inference) using 'x' from the above:
auto (a, _, _) = x; // 'a' is bound too the first element of the tuple 'x', and a can be freely used, the other elements are ignored.
auto (_, _, c) = x; // 'c' is bound too the last element of the tuple 'x', other elements ignored.
auto (_, y, z) = x; // 'y' and 'z' are bound to the second and last element of 'x', others ignored.
auto (f@(_, k, _)) = (1, foo_type(), bar_type()); // 'f' binds to the whole tuple, 'k' binds the second element.
// tuples in functions and tupple patterns in function arguments:
auto make_a_2_tuple(float x, int y) -> (float,int)
{
return (x,y);
}
template < typename FirstType, typename SecondType >
auto first(const (
FirstType,SecondType)
& (x, _)) -> FirstType
return x;
}
template < typename FirstType, typename SecondType >
auto second(const (
FirstType,SecondType)
& (_, x)) -> SecondType
{
return x;
}
// using the above definitions:
auto x = make_a_2_tuple
(0.0f,0);
auto (y,z) = make_a_2_tuple
(0.0f,0);
auto (_,k) = make_a_2_tuple
(0.0f,0);
auto j = (1,1);
int x = second(
j
);
int y = first(
j
);
auto x = ((1,1),2);
auto ((_,y),_) = x;
auto (_, z) = x;
auto k = (x,"foo");
auto (((_,l),_), _) = k;
template < typename X, typename Y, typename Z >
auto swizzle(const (X,(Y,Z))& (x,(y,z))) -> ((Z,Y),X)
{
return ((z,y),x);
}
auto (_, x) = swizzle((1,(2,3));
Not every language abstraction should be forced in to or even make sense as a library abstraction. Why is the community making this so hard? I see no reason why we couldn't have the above any more than we have say lambda expressions and be just as efficient if not more so than a library solution without all the ugly hacks and adding more peculiar language changes to just make the library abstraction work.
Can we please at least try to pursue the possibility.
Not every language abstraction should be forced in to or even make sense as a library abstraction. Why is the community making this so hard? I see no reason why we couldn't have the above any more than we have say lambda expressions and be just as efficient if not more so than a library solution without all the ugly hacks and adding more peculiar language changes to just make the library abstraction work.
Can we please at least try to pursue the possibility.
{int, float, std::string} a = {0, 0.0f, "foo"};
auto a = make_tuple(0, 0.0f, "foo");
for((k, v) : m)
...
for(auto& kv : m)
In many cases C++14 allows std::get<Type>(kv), and it's pretty common
for a map to have a key type that's distinct from the type it maps to.
It's still not perfect, but if I'm iterating over a map<int, string>
then std::get<int>(kv) and std::get<string>(kv) are pretty readable,
IMO.
You missed out the loop body where you have to refer to kv.first and kv.second, not nice names like "key" and "value".
auto& key = key_value_pair.first;
auto& value = key_value_pair.
second;
using
kv.key = kv.first;
using kv.value = kv.second;
concept KeyValue<C> {
typename key_type;
typename value_type;
key_type key;
value_type
value;
}
template<typename T1, typename T2>
concept_map KeyValue<
std::pair<T1, T2>> {
typedef T1 key_type;
typedef T2 value_type;
using key = C.first;
using value = C.second;
}
void f(const std::map<int, std::string>& m) {
for(HasKeyValue& kv : m)
std::cout << "key: " << kv.key << " value: " << kv.value << std::endl;
}
You missed out the loop body where you have to refer to kv.first and kv.second, not nice names like "key" and "value".Well, I'd think it is obvious what a key_value_pair.first is.. (I generally dislike one-letter variable names anyway) Or if you use it in gazillion places inside the loop, you can addAt the beginning of the loop.
auto& key = key_value_pair.first;
auto& value =key_value_pair.
second;
for(HasKeyValue& kv : m)
std::cout << "key: " << key(kv) << " value: " << value(kv) << std::endl;
As proposed, I do not think N3617 would allow something like this:
auto key = []get<0>;
auto value = []get<1>;
but I guess it could be extended.
FWIW, the paper is currently undergoing a slight rehault that would make `[]first` invalue
what is the reason for the change? reserving the []<name> syntax for a
future named lambda proposal?
auto free = []foo; // always calls free function foo, unless in a member context
auto mem = [].foo; // always INVOKE semantics for members
void X::mem_fun(){
auto mem = []foo; // only finds members, with implicit `this` capturing
}
// the following two should be strictly equivalent in any context
foo(args...);
[]foo(args...);
// example of named template type definition
typedef Container <char R, char G, char B, char A> ImageType;
// instantiation: creates 800x600 elements, without knowing the memory layout, could be
// struct {char R, G, B, A; } image[800*600]; or
// struct {char R, G, B, A; } image[800][600]; or
// struct {char R[800*600], G[800*600], B[800*600], A[800*600]; } image;
// etc...
ImageType image({800,600});
// Getting and setting element works regardless of the layout using the field name
image.get<ImageType::A>({0,0}) = 0;
It is possible to achieve this using variadic template/tuples, but the fields have to be addressed directly by index, which is simply unacceptable for a large code base, since the readability and maintainability is awful (think about accessing struct members by index instead of name!). Using enums to alias the indexes is a very short term solution with more inconvenients than benefits in then end.
- generating a uint hash from operator "" _h
- make that available through get. Should already work?
- Overload make_tuple.
Would be great!
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
The proposal to add `std::tuple` is N1382:I guess the Motivation section is what attempts to answer your question.
I dnt want to create a struct for.each database query or for adhoc small data structures that I will use very few times, polluting my public interface with those structs, yet I want to use names to keep fields readable.
Hi
On Saturday, May 17, 2014 5:33:40 PM UTC+12, Andrew Tomazos wrote:The proposal to add `std::tuple` is N1382:
I guess the Motivation section is what attempts to answer your question.
I read the motivation part as suggested. I'm embarrassed to say I don't feel any wiser.
The following represents my opinion:
I dnt want to create a struct for.each database query or for adhoc small data structures that I will use very few times, polluting my public interface with those structs, yet I want to use names to keep fields readable.
Couldn't this be looked on the other way around:instead of adding names to tuple elements to make the whole thing more struct-like you could just as well add some kind of indexing possibility to structs, to make them more tuple-like. At least as far as I have understood it the main advantage that tuples provide over structs is that you can index them with compile time constant indices, which is common in template metaprogramming.
--
---
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/N-kIXNrkTUk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.
- Smaller code, easier to read.- The hash collision problem has been solved : if two members happen to have the same id, name or hash, the compilation will fail.- New internal storage method : base on a std::stuple instead of a recursive class hierachy, allowing for nice and fast interactions with std::tuple.- More generic API, easier to use.This post will sure be of interest to @German Diago. I drastically improved my named tuple prototype since the last time. Changes includes:
Here is a simple example to illustrate what I would like to achieve:
// example of named template type definition
typedef Container <char R, char G, char B, char A> ImageType;
// instantiation: creates 800x600 elements, without knowing the memory layout, could be
// struct {char R, G, B, A; } image[800*600]; or
// struct {char R, G, B, A; } image[800][600]; or
// struct {char R[800*600], G[800*600], B[800*600], A[800*600]; } image;
// etc...
ImageType image({800,600});
// Getting and setting element works regardless of the layout using the field name
image.get<ImageType::A>({0,0}) = 0;
Enjoy code and examples here: https://github.com/duckie/named_tuple.- Smaller code, easier to read.- The hash collision problem has been solved : if two members happen to have the same id, name or hash, the compilation will fail.- New internal storage method : base on a std::stuple instead of a recursive class hierachy, allowing for nice and fast interactions with std::tuple.- More generic API, easier to use.Hello guysThis post will sure be of interest to @German Diago. I drastically improved my named tuple prototype since the last time. Changes includes:
--
Salut Jean-Bernard,Hello Vicente
Thank you very much for your interest about this work.What you propose is actually doable, and is quite similar to what we can found in this project, which basically does the same thing.
I am a little bit reluctant to add this feature for a very particular reason. Using static instances as you propose adds a problem : you have static symbols to manage, thus leading to potential conflicts between different compilation units. Those problems can be solved but extra care about them is needed. For instance, you used an anonymous namespace. It works, but duplicates every static instance in every compilation unit using them. This adds unused data in the resulting compiled code. When using declared (but NOT defined) types, no extra data is added.
The main point of my particular implementation is to avoid static instances as much as possible (cannot be avoided when you want to use runtime introspection, obviously). This allows to use a syntax with wich you dont even have to declare attribute names before using them.
auto test = make_named_tuple(
_<"nom"_h>() = std::string("Roger")
, _<"age"_h>() = 47
, _<"taille"_h>() = 1.92
, _<"liste"_h>() = std::vector<int>({1,2,3})
);
What is your opinion on this point ?
My mind is always open to changes, and I do like the proposal about using key selector function to access members. This really is elegant, I'll think about it.
--
As for tagged types into the standard, I am convinced they will make their way through one day or antoher. Tuple addressing via type was the first baby step toward it. Yes I would gladly see them well integrated with std::exprimental::any and std::experimental::variant. And to be fully honest, I just see them as a step toward anonymous structures : a type described by its members' names and types, but not by its own name.And yes, we could add what you propose just on top of what already exists : this convinces me to give it a try very soon.Hi again :)
Yes, the IOD project uses macros, and I dont like it either.
It would spare the developpers a lot of conversion code to make libraries from different sources interoperable. Thats what I had in mind while working on the named tuple.
I dont think anything prevents from extending std::tuple with tagged types. I did not use inheritance because the first implementation was not based on std::tuple.. But now that you state it, it makes sense.
I did not plan to write a proposal for the next meeting, but I can spare time to. I am not used to the exercise though, any advice on the matter will be appreciated.
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.