39

I want to use a triplet class, as similar as possible to std::pair. STL doesn't seem to have one. I don't want to use something too heavy, like Boost. Is there some useful FOSS non-restrictive-license triplet class I could lift from somewhere? Should I roll my own? Should I do something else entirely?

Edit: About std::tuple...

Is there really no benefit to a triplet-specific class? I mean, with tuple, I can't do

template<typename T1, typename T2, typename T3> std::tuple<T1, T2, T3> triple;

now can I? Won't I have to typedef individual-type-combination triples?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 3
    I'd say `std::tuple`. – chris Dec 20 '13 at 14:23
  • 3
    If for some reason you do not have access to `std::tuple` (non-C++11 compliant compiler, for instance), consider `std::pair >`. – Frédéric Hamidi Dec 20 '13 at 14:35
  • @FrédéricHamidi: That would make element references quite cumbersome and uninituitive. – einpoklum Dec 20 '13 at 14:56
  • 2
    But element references are already unintuitive with `std::pair`. How often do you really want elements called `first` and `second` (rather than e.g. `key` and `value`, or `name` and `surname`). – James Kanze Dec 20 '13 at 14:59
  • @JamesKanze: `mytriple.second.second` is much more confusing than `mytriple.third`. – einpoklum Dec 20 '13 at 15:14
  • @einpoklum True. But it's rare that either would be appropriate. Perhaps in some numeric applications, but otherwise: it's better to signal semantic intent directly. – James Kanze Dec 20 '13 at 15:23
  • It is hilarious that, with all the talk (here and below) of convenience/inconvenience of accessing members of a std::tuple, nobody actually demonstrated the accessor syntax! – welch Feb 23 '19 at 00:56

5 Answers5

53

No, don't roll your own. Instead, take a look at std::tuple - it's a generalization of std::pair. So here's a value-initialized triple of ints:

std::tuple<int, int, int> triple;

If you want, you can have a type alias for triples only:

template<typename T1, typename T2, typename T3>
using triple = std::tuple<T1, T2, T3>;
einpoklum
  • 118,144
  • 57
  • 340
  • 684
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
7

If you can use C++11, use std::tuple

If not, use boost::tuple

6

If you're using C++11, you can use std::tuple.

If you're using C++03, then you'll either need to resort to rolling your own (which isn't too hard), or using tuple from Boost.

Michael Kristofik
  • 34,290
  • 15
  • 75
  • 125
John Dibling
  • 99,718
  • 31
  • 186
  • 324
4

I think you need something like this:

template<typename T>
struct triplet
{
    T first, middle, last;
};

template<typename T>
triplet<T> make_triplet(const T &m1, const T &m2, const T &m3) 
{
    triplet<T> ans;
    ans.first = m1;
    ans.middle = m2;
    ans.last = m3;
    return ans;
}

Examples of usage:

triplet<double> aaa;
aaa = make_triplet<double>(1.,2.,3.);
cout << aaa.first << " " << aaa.middle << " "  << aaa.last << endl;

triplet<bool> bbb = make_triplet<bool>(false,true,false);
cout << bbb.first << " " << bbb.middle << " "  << bbb.last << endl;

I'm using this and it is enough for my purposes... If you want different types, though, just do some modifications:

template<typename T1, typename T2, typename T3>
struct triplet
{
    T1 first; 
    T2 middle;
    T3 last;
};

template<typename T1, typename T2, typename T3>
triplet<T1,T2,T3> make_triplet(const T1 &m1, const T2 &m2, const T3 &m3) 
{
    triplet<T1,T2,T3> ans;
    ans.first = m1;
    ans.middle = m2;
    ans.last = m3;
    return ans;
}

And the usage will be very similar:

triplet<bool,string,myDouble> ccc;
ccc = make_triplet<bool,string,double>(false,"AB",3.1415);
ccc.middle = "PI";
cout << ccc.first << " " << ccc.middle << " "  << ccc.last << endl;
iperetta
  • 607
  • 10
  • 19
  • There is a small mistake in your code. The definition of `make_triplet` should be `triplet make_triplet(const T1 &m1, const T2 &m2, const T3 &m3)` – user1956185 Dec 01 '17 at 14:19
  • Get error message when I use: `vector< triplet > v; v.emplace_back(1,2,3);` – Neo li Aug 12 '21 at 06:43
-1

To add the aspect of similarity to std::pair, you could define a class that has first, second and third. My guess is that in In that case you cannot avoid making a subclass of std::pair and add a 'third' member. It's a few lines of code.

Furthermore, if you often use these things with the same type, you could make twins and triplet classes as well. Easily made with C++-11's 'using', like:

template <typename T> using twins = std::pair<T,T>;
Bert Bril
  • 371
  • 2
  • 12
  • Oh no, a triplet class should definitely not be a subclass of `std::pair`. A triplet is not a kind-of-a-pair, like a `std::pair` is not a subclass of `T` nor of `U`. – einpoklum Jun 13 '17 at 11:23
  • I don't see your point. A twin is a pair where Tand U are the same class, triplet has 3 of the same type. Any triplet can be usef where any twin can be usef. – Bert Bril Jun 14 '17 at 14:47
  • That is absolutely not true. With a pair, you rely on there being exactly two pieces of data; with a triplet, you make a contradictory assumption. Not only can they not be subclasses, but they cannot be used interchangeably. – einpoklum Jun 14 '17 at 16:04
  • Sorry I disagree. Anywhere you need a twin you can use a triplet, but not the other way around. That's exactly the idea of inheritance, the LSK applies perfectly. Moreover, because the members are called 'first' and 'second' parameterized functions and classes get exactly what they need from a pair even when in fact they operate on a triplet. Very standard and very OK. – Bert Bril Jun 16 '17 at 06:35