I'm trying to mimic the behavior of tie pre C++11.
pair<int, int> test() {
return make_pair(13, 42);
}
int main() {
int a = 1, b = 2;
pair<int&, int&>(a, b) = test();
cout << a << ' ' << b << endl;
}
This works however if I use make_pair instead to the pair constructor a and b are not assigned.
Why does the pair constructor work but not make_pair?
Actually you can use std::make_pair. But you need to implement reference_wrapper class to imitate reference. Examplary (not very polished, but working as expected) c++03 approach:
#include <iostream>
#include <utility>
using namespace std;
template <class T>
struct reference_wrapper {
bool is_const;
T* v;
T const* cv;
reference_wrapper(T& t): v(&t), is_const(false) { }
reference_wrapper(T const& t): cv(&t), is_const(true) { }
reference_wrapper &operator=(reference_wrapper const &rw) {
if (rw.is_const) {
*v = *rw.cv;
} else {
*v = *rw.v;
}
}
};
template <class T>
reference_wrapper<T> ref(T &t) {
return reference_wrapper<T>(t);
}
pair<int, int> test() {
return make_pair(13, 42);
}
int main() {
int a = 1, b = 2;
//pair<int&, int&>(a, b) = test(); // works
make_pair(ref(a), ref(b)) = test(); // now it does work
std::cout << a << ' ' << b << std::endl;
}
In 20.2.2[lib.pairs]8 the standard states that pair uses "explicit types" while make_pair's "types are deduced".
This is why the standard defines a constructor for pair:
template <class T1, class T2>
pair(const T1& x, const T2& y)
If you run your code on a C++03 compiler you will get this error:
non-static reference member int& std::pair<int&, int&>::first, can't use default assignment operator
The problem is that pair uses an implicitly-declared copy assignment operator which is not defined if the pair:
Has a non-static data member of a reference type
Whether defined by make_pair or the pair constructor, the template arguments will define both of the pair's members as int& so the implicitly-declared copy assignment operator will not be defined. So this cannot be accomplished with a pair in C++03.
If using return parameter is undesirable, you can write your own implementation of tie:
template <class T1, class T2>
struct tie{
T1& first;
T2& second;
tie(T1& x, T2& y) : first(x), second(y) {}
tie<T1, T2>& operator=(const pair<T1, T2>& rhs){
first = rhs.first;
second = rhs.second;
return *this;
}
};
This will allow assignment of a pair:
tie<int, int>(a, b) = test();
To get the exact C++11 behavior which doesn't require template arguments you'll need to define a function. If tie is nested in namespace details the function can be defined as:
template <class T1, class T2>
details::tie<T1, T2> tie(T1& x, T2& y) {
return details::tie<T1, T2>(x, y);
}
This will allow assignment of a pair just as in C++11:
tie(a, b) = test();
Live Example
Note that this is still intolerant of using int& template arguments, so details::tie<int&, int&> and tie<int&, int&> will fail just as before.
make_pair produces a pair of values, not references. That means it would produce pair<int, int> in your example and you'd be assigning results of test() to a temporary variable¹.
You can mimic tie with the following:
template<typename T, typename U>
std::pair<T&, U&> tie_pair(T& l, U& r)
{
return std::pair<T&, U&>(l, r);
}
http://ideone.com/muAcaG
¹ this is an unfortunate side-effect of C++03 not having ref-qualifiers. In C++≥11 you can delete operator= for rvalue this (in non-std classes) and make such cases a compiler error rather than silent surprising behaviour.
Related
I'm pretty new in C++. I have wrote a function template to sum all elements in a vector like this:
template<typename T>
inline T sumator(const std::vector<T> &sequence) {
T init = T{};
return accumulate(sequence.begin(), sequence.end(), init);
}
All work well until the default constructor is not declare, but declare constructor from, for example, 2 arguments.
Like this:
class A {
private:
int a;
int b;
public:
// A() = default;
A(int aa, int bb) : a(aa),b(bb){};
A operator+(const A &right) const {
return {a + right.a, b + right.b};
}
bool operator==(const A &right) const {
return (a == right.a && b == right.b);
}
};
vector<A> bc = {{3,5},{5,5}};
A res = Adder::sumator(works);
A result = {8,10};
assert(result,res);
Now I get an error like : error: no matching constructor for initialization of 'A'
T init = T{};
How can I avoid this situation, not using https://en.cppreference.com/w/cpp/types/is_default_constructible
UPD: I have many classes, some of them with default constructor, some without but with constructor for 2 arg, some for 3, e.t.c. And I want to accumulate every situation well
Possible solutions that I can think of.
Let users rely on std::accumulate by providing an initial vlaue.
Provide an overload of sumator with an initial value. Users can call the overload with an initial value if they have a type that does not have default constructor.
Insist that the type for which the function is invoked have a default consructor.
template<typename T>
inline T sumator(const std::vector<T> &sequence, T init) {
return accumulate(sequence.begin(), sequence.end(), init);
}
template<typename T>
inline T sumator(const std::vector<T> &sequence) {
return accumulate(sequence.begin(), sequence.end(), {});
}
You can add another parameter with default argument.
template<typename T>
inline T sumator(const std::vector<T> &sequence, const T& init = T{}) {
return accumulate(sequence.begin(), sequence.end(), init);
}
For types could be default-constructed you can still
sumator(some_vector);
And specify the default value when T can't be default-constructed. e.g.
sumator(some_vector, A{0, 0});
You can split it in two overloads and add a static_assert to provide a nice compilation error message if someone tries to use it the wrong way.
One overload would be valid only if the type is default constructible and one overload would be valid for types that is not as well as for those that are:
#include <type_traits>
#include <vector>
template<typename T>
T sumator(const std::vector<T>& sequence) {
static_assert(std::is_default_constructible_v<T>);
return std::accumulate(sequence.begin(), sequence.end(), T{});
}
template<typename T>
T sumator(const std::vector<T>& sequence, const T& init) {
return std::accumulate(sequence.begin(), sequence.end(), init);
}
Another option is to add a default argument that can be used for types that are default constructible - and you could also make it more generic to make it work with not only vectors but with lists etc.
template<template<class, class...> class C, class T, class... Ts>
T sumator(const C<T, Ts...>& sequence, const T& init = T{}) {
return std::accumulate(sequence.begin(), sequence.end(), init);
}
As You may (not) know using std::minmax with auto and temporary arguments may be dangerous. Following code for example is UB because std::minmax returns pair of references, not values:
auto fun(){
auto res = std::minmax(3, 4);
return res.first;
}
I would like to ask if there is possibility to make std::minmax function act safely or at least safer without any overhead? I came up with a solution like this, but I am not completely sure if it is equivalent to current minmax as generated assembly is different for stl-like implementation and mine. So the question is: what are the possible problems/drawbacks of my implementation of minmax in relation to std-like one:
//below is std-like minmax
template< class T >
constexpr std::pair<const T&,const T&> std_minmax( const T& a, const T& b ){
return (b < a) ? std::pair<const T&, const T&>(b, a)
: std::pair<const T&, const T&>(a, b);
}
//below is my minmax implementation
template< class T >
constexpr std::pair<T, T> my_minmax( T&& a, T&& b ){
return (b < a) ? std::pair<T, T>(std::forward<T>(b), std::forward<T>(a))
: std::pair<T, T>(std::forward<T>(a), std::forward<T>(b));
}
Live demo at godbolt.org
As some of You claim it is unclear what I am asking, I would like to reword a bit what I want. I would like to write function which works exactly like std::minmax, but if given one temporary value - returns std::pair<T, T> instead of std::pair<const T &, const T &>. Secondly, while doing it I would like to avoid any unnecessary moving, copying of data and so forth.
I am not exactly sure what are you trying to achieve. You wrote:
without any overhead
but your solution will copy lvalue arguments. Is it what you want?
Anyway, you cannot use two forwarding references with the same template parameter this way, since it will fail if both function arguments have different categories:
template <typename T> void f(T&& a, T&& b) { }
int main() {
int a = 3;
f(a, 1); // error: template argument deduction/substitution failed
}
For the first function argument, T would be deduced as int&, and for second as int.
If you want to remove any copying, the only possibility is the member of the resulting pair to be:
a (const) lvalue reference to the corresponding function argument in case it is an lvalue,
a value moved from that argument if is it an rvalue.
I don't think this is possible to achieve. Consider:
std::string a("hello");
auto p = minmax(a, std::string("world"));
Here the resulting type would be std::pair<std::string&, std::string>. However, in case of
auto p = minmax(a, std::string("earth"));
the resulting type would be different, namely std::pair<std::string, std::string&>.
Therefore, the resulting type would depend on a runtime condition (which generally requires runtime polymorphism).
UPDATE
Out of curiosity, I just came up with a wrapper that can hold some object either by (const) pointer or by value:
template <typename T>
class val_or_ptr {
std::variant<T, const T*> v_;
public:
val_or_ptr(const T& arg) : v_(&arg) { }
val_or_ptr(T&& arg) : v_(std::move(arg)) { }
const T& get() const { return v_.index() ? *std::get<const T*>(v_) : std::get<T>(v_); }
};
With that, you can define minmax as:
template <typename T, typename U,
typename V = std::enable_if_t<std::is_same_v<std::decay_t<T>, std::decay_t<U>>, std::decay_t<T>>>
std::pair<val_or_ptr<V>, val_or_ptr<V>> minmax(T&& a, U&& b) {
if (b < a) return { std::forward<U>(b), std::forward<T>(a) };
else return { std::forward<T>(a), std::forward<U>(b) };
}
Live demo is here: https://wandbox.org/permlink/N3kdI4hzllBGFWVH
This is very basic implementation, but it should prevent copying both from lvalue and rvalue arguments of minmax.
One solution is when T is an r-value reference then copy it instead of returning an r-value reference:
#include <utility>
template<class T>
std::pair<T, T> minmax(T&& a, T&& b) {
if(a < b)
return {a, b};
return {b, a};
}
When the argument is an r-value reference T is deduced as a non-reference type:
int main() {
int a = 1;
int const b = 2;
minmax(1, 1); // std::pair<int, int>
minmax(a, a); // std::pair<int&, int&>
minmax(b, b); // std::pair<const int&, const int&>
}
With C++17 it is possible to use constexpr if to tie lvalue args and copy everything else. With C++11 I would probably think twice before building an angle brackets moster with a scary look for such a simple use case.
godbolt, coliru
template <typename T>
decltype(auto) minmax(T&& x, T&& y)
{
if constexpr(std::is_lvalue_reference_v<decltype(x)>)
return std::minmax(std::forward<T>(x), std::forward<T>(y));
else {
auto const res = std::minmax(x, y);
return std::make_pair(res.first, res.second);
}
}
To support mixed l/r values you probably need two template params, 4 cases in the if/else, and std::cref(res.xxx) as an argument to std::make_pair for partial.
The Problem
I have a custom type A who has natural ordering (having operator<) and multiple alternative orderings (case-sensitive, case-insensitive, etc.). Now I have a std::pair (or std::tuple) consisting (one or more of) A. Here are some examples of types I want to compare: std::pair<A, int>, std::pair<int, A>, std::tuple<A, int, int>, std::tuple<int, A, int>. How can I compare the std::pair (or std::tuple) using the default element-wise comparison implementation, plugging-in my comparison function for A?
The Code
The code below doesn't compile:
#include <utility> // std::pair
#include <tuple> // std::tuple
#include <iostream> // std::cout, std::endl
struct A
{
A(char v) : value(v) {}
char value;
};
// LOCATION-1 (explained in the text below)
int main()
{
std::cout
<< "Testing std::pair of primitive types: "
<< (std::pair<char, int>('A', 1)
<
std::pair<char, int>('a', 0))
<< std::endl;
std::cout
<< "Testing std::tuple of primitive types: "
<< (std::tuple<char, int, double>('A', 1, 1.0)
<
std::tuple<char, int, double>('a', 0, 0.0))
<< std::endl;
// This doesn't compile:
std::cout
<< "Testing std::pair of custom types: "
<< (std::pair<A, int>('A', 1)
<
std::pair<A, int>('a', 0))
<< std::endl;
return 0;
}
It is because operator< isn't defined for struct A. Adding it to LOCATION-1 above would solve the problem:
bool operator<(A const& lhs, A const& rhs)
{
return lhs.value < rhs.value;
}
Now, we have an alternative ordering for struct A:
bool case_insensitive_less_than(A const& lhs, A const& rhs)
{
char const lhs_value_case_insensitive
= ('a' <= lhs.value && lhs.value <= 'z'
? (lhs.value + 0x20)
: lhs.value);
char const rhs_value_case_insensitive
= ('a' <= rhs.value && rhs.value <= 'z'
? (rhs.value + 0x20)
: rhs.value);
return lhs_value_case_insensitive < rhs_value_case_insensitive;
}
Supposed we want to keep the original operator< for struct A (the case-sensitive one), how can we compare std::pair<A, int> with this alternative ordering?
I know that adding a specialized version of operator< for std::pair<A, int> solves the problem:
bool operator<(std::pair<A, int> const& lhs, std::pair<A, int> const& rhs)
{
return (case_insensitive_less_than(lhs.first, rhs.first)
? true
: case_insensitive_less_than(rhs.first, lhs.first)
? false
: (lhs.second < rhs.second));
}
However, I consider this a sub-optimal solution.
Firstly, for std::pair, it is easy to re-implement the element-wise comparison, but for std::tuple it might be complicated (dealing with variadic templates) and error-prone.
Secondly, I can hardly believe that it is the best-practice way to solve the problem: imagine that we have to define a specialized version of operator< for each of the following classes: std::tuple<A, int, int>, std::tuple<int, A, int>, std::tuple<int, int, A>, std::tuple<A, A, int>, ... (It's not even a practical way!)
Re-using the well written built-in operator< for std::tuple and plugging-in my less-than for struct A would be what I want. Is it possible? Thanks in advance!
The easy way would be to manually write compare( tup, tup, f ) that uses f to lexographically compare the elements in the tuples. But that is boring.
// This type wraps a reference of type X&&
// it then overrides == and < with L and E respectively
template<class X, class L, class E>
struct reorder_ref {
using ref = reorder_ref;
X&& x;
friend bool operator<(ref lhs, ref rhs) {
return L{}((X&&) lhs.x, (X&&) rhs.x);
}
friend bool operator==(ref lhs, ref rhs) {
return E{}((X&&) lhs.x, (X&&) rhs.x);
}
// other comparison ops based off `==` and `<` go here
friend bool operator!=(ref lhs, ref rhs){return !(lhs==rhs);}
friend bool operator>(ref lhs, ref rhs){return rhs<lhs;}
friend bool operator<=(ref lhs, ref rhs){return !(lhs>rhs);}
friend bool operator>=(ref lhs, ref rhs){return !(lhs<rhs);}
reorder_ref(X&& x_) : x((X&&) x_) {}
reorder_ref(reorder_ref const&) = default;
};
the above is a reference that changes how we order.
// a type tag, to pass a type to a function:
template<class X>class tag{using type=X;};
// This type takes a less than and equals stateless functors
// and takes as input a tuple, and builds a tuple of reorder_refs
// basically it uses L and E to compare the elements, but otherwise
// uses std::tuple's lexographic comparison code.
template<class L, class E>
struct reorder_tuple {
// indexes trick:
template<class Tuple, class R, size_t... Is>
R operator()(tag<R>, std::index_sequence<Is...>, Tuple const& in) const {
// use indexes trick to do conversion
return R( std::get<Is>(in)... );
}
// forward to the indexes trick above:
template<class... Ts, class R=std::tuple<reorder_ref<Ts const&, L, E>...>>
R operator()(std::tuple<Ts...> const& in) const {
return (*this)(tag<R>{}, std::index_sequence_for<Ts...>{}, in);
}
// pair filter:
template<class... Ts, class R=std::pair<reorder_ref<Ts const&, L, E>...>>
R operator()(std::pair<Ts...> const& in) const {
return (*this)(tag<R>{}, std::index_sequence_for<Ts...>{}, in);
}
};
the above stateless function object takes some new less and equals operations, and maps any tuple to a tuple of reorder_ref<const T, ...>, which change the ordering to follow L and E respectively.
This next type does what std::less<void> does for std::less<T> sort of -- it takes a type-specific stateless ordering function template object, and makes it a type-generic stateless ordering function object:
// This takes a type-specific ordering stateless function type, and turns
// it into a generic ordering function type
template<template<class...> class order>
struct generic_order {
template<class T>
bool operator()(T const& lhs, T const& rhs) const {
return order<T>{}(lhs, rhs);
}
};
so if we have a template<class T>class Z such that Z<T> is an ordering on Ts, the above gives you a universal ordering on anything.
This next one is a favorite of mine. It takes a type T, and orders it based on a mapping to a type U. This is surprisingly useful:
// Suppose there is a type X for which we have an ordering L
// and we have a map O from Y->X. This builds an ordering on
// (Y lhs, Y rhs) -> L( O(lhs), O(rhs) ). We "order" our type
// "by" the projection of our type into another type. For
// a concrete example, imagine we have an "id" structure with a name
// and age field. We can write a function "return s.age;" to
// map our id type into ints (age). If we order by that map,
// then we order the "id" by age.
template<class O, class L = std::less<>>
struct order_by {
template<class T, class U>
bool operator()(T&& t, U&& u) const {
return L{}( O{}((T&&) t), O{}((U&&) u) );
}
};
Now we glue it all together:
// Here is where we build a special order. Suppose we have a template Z<X> that returns
// a stateless order on type X. This takes that ordering, and builds an ordering on
// tuples based on it, using the above code as glue:
template<template<class...>class Less, template<class...>class Equals=std::equal_to>
using tuple_order = order_by< reorder_tuple< generic_order<Less>, generic_order<Equals> > >;
tuple_order does most of the work for us. All we need is to provide it with an element-wise ordering template stateless function object. tuple_order will then produce a tuple ordering functor based on it.
// Here is a concrete use of the above
// my_less is a sorting functiont that sorts everything else the usual way
// but it sorts Foo's backwards
// Here is a toy type. It wraps an int. By default, it sorts in the usual way
struct Foo {
int value = 0;
// usual sort:
friend bool operator<( Foo lhs, Foo rhs ) {
return lhs.value<rhs.value;
}
friend bool operator==( Foo lhs, Foo rhs ) {
return lhs.value==rhs.value;
}
};
template<class T>
struct my_less : std::less<T> {};
// backwards sort:
template<>
struct my_less<Foo> {
bool operator()(Foo const& lhs, Foo const& rhs) const {
return rhs.value < lhs.value;
}
};
using special_order = tuple_order< my_less >;
and bob is your uncle (live example).
special_order can be passed to a std::map or std::set, and it will order any tuples or pairs encountered with my_less replacing the default ordering of the elements.
Is it possible to return an empty pair from a function? Meaning, follow the rules of the function prototype, but do not have any elements in the pair (e.g. NULL). Understanding that a pair simply exists so I don't know if this is conceptually possible. I have a need to return a pair that is NULL or empty, if that makes any sense.
For example,
pair<int, int> MyClass::someFunction()
{
// do something that means we need to return an empty pair
return NULL; // <--- this does not work obviously
}
Unfortunately, boost is not a possibility for me.
Generally speaking an empty pair doesn't even make sense. Afterall a pair is per definition a container containing two objects.
You could however make something like an empty pair using Boost.Optional. Then you would either use a boost::optional<std::pair<...>> giving you the option of returning either a pair or an empty state or use std::pair<boost::optional<...>, boost::optional<...>> for a pair where either object could be empty.
You can returns pointer... Or use boost::optional<T>. Optional will be better...
boost::optional<std::pair<int, int> > MyClass::someFunction()
{
return boost::optional<std::pair<int, int> >();
}
void f(const MyClass& f)
{
boost::optional<std::pair<int, int> > ret = f.someFunction();
if (!ret) // empty
{
...
}
}
The answer to your questions is easily explained by considering the way the C++ compiler generates code in this case.
The std::pair<int, int> is returned-by-value.
Since MyClass::someFunction() is returning an object by value, the sequence of events is as follows:
The calling function reserves space on the stack for a std::pair<int, int>
The MyClass::someFunction() is called
The right hand side of the return statement is a assignment to the location reserved on the stack earlier. There is an implicit construction of a std::pair<int, int> taking place.
Thus returning a NULL pointer is impossible.
It wouldn't take much to create your own "optional pair" (similar to boost::optional<std::pair<…>>, but with a different interface), e.g.:
template <typename T1, typename T2> struct OptPair : std::pair<T1, T2>
{
typedef std::pair<T1, T2> base_t;
bool contains;
OptPair() : contains(true) {}
explicit OptPair(bool x) : contains(x) {}
OptPair(const T1& x, const T2& y) : base_t(x, y), contains(true) {}
template <class U, class V>
OptPair(const std::pair<U,V> &p) : base_t(p), contains(true) {}
template <class U, class V> OptPair(const OptPair<U,V> &p) : base_t(p), contains(p.contains) {}
// No need to define operator=, as the default will construct an OptPair<T1, T2>
// if necessary, then copy members into *this.
};
template <typename T1, typename T2>
OptPair<T1, T2> makeOptPair() { return OptPair<T1, T2>(); }
template <typename T1, typename T2>
OptPair<T1, T2> makeOptPair(const T1 &x, const T2 &y) {
OptPair<T1, T2> p(true);
p.first = x;
p.second = y;
return p;
}
template <typename OS, typename T1, typename T2>
OS &operator<<(OS &os, const OptPair<T1, T2>& p) {
os << "<OptPair: ";
if (p.contains) os << p.first << ", " << p.second;
else os << "empty";
os << ">";
return os;
}
Then you can use it just like std::pair (and even use it interchangeably with std::pair, assigning values back and forth), but with the added ability to pass an "empty" value back like this:
OptPair<int, int> someFunction()
{
...
return OptPair<int, int>(false);
}
You have to make sure to check the result before using it, like this:
void doStuffWithPair(std::pair<int, int>);
void doStuffWithEmpty();
...
OptPair<int, int> ret = someFunction();
if (ret.contains) doStuffWithPair(ret);
else doStuffWithEmpty();
A pair, by definition, has 2 elements. It cannot have none.
You need something like boost::optional<std::pair<T1,T2>>. Then you can choose to have a pair or not. You can find documentation for boost::optional here.
Is it valid to have a std::pair of references ? In particular, are there issues with the assignment operator ? According to this link, there seems to be no special treatment with operator=, so default assignement operator will not be able to be generated.
I'd like to have a pair<T&, U&> and be able to assign to it another pair (of values or references) and have the pointed-to objects modified.
In C++11 you can use std::pair<std::reference_wrapper<T>, std::reference_wrapper<U>> and the objects of that type will behave exactly as you want.
No, you cannot do this reliably in C++03, because the constructor of pair takes references to T, and creating a reference to a reference is not legal in C++03.
Notice that I said "reliably". Some common compilers still in use (for GCC, I tested GCC4.1, #Charles reported GCC4.4.4) do not allow forming a reference to a reference, but more recently do allow it as they implement reference collapsing (T& is T if T is a reference type). If your code uses such things, you cannot rely on it to work on other compilers until you try it and see.
It sounds like you want to use boost::tuple<>
int a, b;
// on the fly
boost::tie(a, b) = std::make_pair(1, 2);
// as variable
boost::tuple<int&, int&> t = boost::tie(a, b);
t.get<0>() = 1;
t.get<1>() = 2;
I think it would be legal to have a std::pair housing references. std::map uses std::pair with a const type, after all, which can't be assigned to either.
I'd like to have a pair<T&, U&> and be able to assign to it another pair
Assignment won't work, since you cannot reset references. You can, however, copy-initialize such objects.
You are right. You can create a pair of references, but you can't use operator = anymore.
I was thinking along the same lines as you, I think. I wrote the following class to scratch this particular itch:
template <class T1, class T2> struct refpair{
T1& first;
T2& second;
refpair(T1& x, T2& y) : first(x), second(y) {}
template <class U, class V>
refpair<T1,T2>& operator=(const std::pair<U,V> &p){
first=p.first;
second=p.second;
return *this;
}
};
It allows you to do horrible things like:
int main (){
int k,v;
refpair<int,int> p(k,v);
std::map<int,int>m;
m[20]=100;
m[40]=1000;
m[60]=3;
BOOST_FOREACH(p,m){
std::cout << "k, v = " << k << ", " << v << std::endl;
}
return 0;
}
(remember the relevant includes).
The nastiness is of course that the references to k and v that I am assigning to are hidden inside p.
It almost becomes pretty again if you do something like this:
template <class T1,class T2>
refpair<T1,T2> make_refpair (T1& x, T2& y){
return ( refpair<T1,T2>(x,y) );
}
Which allows you to loop like this:
BOOST_FOREACH(make_refpair(k,v),m){
std::cout << "k, v = " << k << ", " << v << std::endl;
}
(All comments are welcome as I am in no way a c++ expert.)
I don't know what is "wrong" with std::pair in C++03 but if I reimplement it naively, I don't have any problem with it, (using the same compiler gcc and clang).
double a = 1.;
double b = 2.;
my::pair<double, double> p1(5., 6.);
my::pair<double&, double&> p2(a, b);
p2 = p1; // a == 5.
So a workaround could be to (1) reimplement pair (in a different namespace), or (2) specialize for std::pair<T&, T&>, or (3) simply use C++11 (where std::pair for refs works out of the box)
(1) Here it is the naive implementation
namespace my{
template<class T1, class T2>
struct pair{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(T1 const& t1, T2 const& t2) : first(t1), second(t2){}
template<class U1, class U2> pair(pair<U1, U2> const& p) : first(p.first), second(p.second){}
template<class U1, class U2>
pair& operator=(const pair<U1, U2>& p){
first = p.first;
second = p.second;
return *this;
}
};
template<class T1, class T2>
pair<T1, T2> make_pair(T1 t1, T2 t2){
return pair<T1, T2>(t1, t2);
}
}
(2) And here it is an specialization of std::pair (some people may complain that I am messing around overloading/specializing with the std namespace, but I think it is ok if it is to extend the capabilities of the class)
namespace std{
template<class T1, class T2>
struct pair<T1&, T2&>{
typedef T1& first_type; /// #c first_type is the first bound type
typedef T2& second_type; /// #c second_type is the second bound type
first_type first;
second_type second;
pair(T1& t1, T2& t2) : first(t1), second(t2){}
template<class U1, class U2> pair(pair<U1, U2> const& p) : first(p.first), second(p.second){}
template<class U1, class U2>
pair& operator=(const pair<U1, U2>& p){
first = p.first;
second = p.second;
return *this;
}
};
}
Maybe I am missing something obvious, I can edit the answer if some obvious flaws, are pointed.
Post c++14, you can do:
int a, b;
auto const p(std::make_pair(std::ref(a), std::ref(b)));
Using std::cref() is also possible.
I ended up solving a similar problem by just building a really simple structure. I didn't even worry about the assignment operator since the default one should work fine.
template<class U, class V>
struct pair
{
pair(U & first, V & second): first(first), second(second) {}
U & first;
V & second;
}