简体   繁体   中英

std::tuple of member pointer behavior

I would like to understand the reason of this behavior:

This code works perfect:

#include <iostream>
#include <tuple>

struct SomeClass {
 int v1;
 int v2;
 int v3;
};


auto pv1 = &SomeClass::v1;
auto pv2 = &SomeClass::v2;
auto pv3 = &SomeClass::v3;

auto t = std::tie(pv1, pv2, pv3);

int main() {

  SomeClass c;
  c.v1 = 111;
  c.v2 = 222;
  c.v3 = 333;

  std::cout << c.*std::get<0>(t) << std::endl << c.*std::get<1>(t) << std::endl << c.*std::get<2>(t) << std::endl;
}

but this doesn't compile

#include <iostream>
#include <tuple>

struct SomeClass {
 int v1;
 int v2;
 int v3;
};

auto t = std::tie(&SomeClass::v1, &SomeClass::v2, &SomeClass::v3);

int main() {

  SomeClass c;
  c.v1 = 111;
  c.v2 = 222;
  c.v3 = 333;

  std::cout << c.*std::get<0>(t) << std::endl << c.*std::get<1>(t) << std::endl << c.*std::get<2>(t) << std::endl;
}

with the following error in gcc

test.cpp:17:65: error: invalid initialization of non-const reference of type ‘int SomeClass::*&’ from an rvalue of type ‘int SomeClass::*’
 auto t = std::tie(&SomeClass::v1, &SomeClass::v2, &SomeClass::v3);
                                                                 ^
In file included from test.cpp:2:0:
/usr/include/c++/4.8/tuple:1044:5: error: in passing argument 1 of ‘std::tuple<_Elements& ...> std::tie(_Elements& ...) [with _Elements = {int SomeClass::*, int SomeClass::*, int SomeClass::*}]’
     tie(_Elements&... __args) noexcept
     ^

BACKGROUND PROBLEM: As you can suspect, I want to group some members of some Class in tuples to do some template magic.

If we look at the cppreference documentation for std::tie it says ( emphasis mine ):

 template< class... Types > tuple<Types&...> tie( Types&... args ); 

Creates a tuple of lvalue references to its arguments or instances of std::ignore.

In your first case pv1 , pv2 and pv3 are all lvalues, therefore it is valid to bind a non-const lvalue reference to them.

In your second case you are passing rvalues and so you can not bind a non-const lvalue reference to them. You can make this work by using std::make_tuple :

auto t = std::make_tuple(&SomeClass::v1, &SomeClass::v2, &SomeClass::v3);

and we can see it is indeed valid to pass rvalue references to make_tuple :

 template< class... Types > tuple<VTypes...> make_tuple( Types&&... args ); ^^ 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM