1

I was trying to pass a tuple of two different vectors as the attribute to a Spirit X3 rule. One sensible way to do this seemed to be to wrap these in a forward_as_tuple, since I only want to pass the references. That worked out nicely, but I had to write a separat variable declaration and then pass it on since the non-const temporary lifetime rules would bite me otherwise.

In the end, I ended up writing something like as_const(std::forward_as_tuple(ourBoxes, scoreVals)). By making the temporary const, I can pass it on. The temporary is const -- since all element types are references, that is more or less a given.

This makes me wonder, is there any design rationale for making the forward_as_tuple return type non-const? Or put another way, how can you validly mutate a tuple of only reference types?

EDIT: Added a proper example, below. This relates back to the fact that I want to use X3, and the attribute type in X3 is always a reference, so passing the attribute by value instead is not an option. The wider question is still, is there any reason for forward_as_tuple having a non-const return type.

#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>

using namespace boost::spirit;
using namespace std;

// Coming in C++ 17
template <class T>
constexpr std::add_const_t<T>& as_const(const T& t) noexcept
{
    return t;
}

int main()
{
    int x, y;
    string readme = "42 43";
    // Doesn't work
    // phrase_parse(readme.begin(), readme.end(), x3::int_ > x3::int_,
    //       x3::space, forward_as_tuple(x, y));
    // Works:
    phrase_parse(readme.begin(), readme.end(), x3::int_ > x3::int_,
            x3::space, as_const(forward_as_tuple(x, y)));

    // Is there any reason for forward_as_tuple not returning a const?
    // i.e. some use case where forward_as_tuple HAS to return a non-const for
    // proper operation
}
cnettel
  • 1,024
  • 5
  • 7
  • 3
    I don't understand the question. Can you provide an [MCVE]? Why are you worried about lifetime when you just have a tuple of references? (Also unclear if Spirit is relevant?) – Barry Nov 01 '17 at 14:11
  • Any function call of the sort `funcName(forward_tuple(x,y));` (where `funcName` is not explicitly requiring a `const` argument) will be hit by this: https://stackoverflow.com/questions/6967927/non-const-reference-may-only-be-bound-to-an-lvalue *I* do not worry about lifetime, but the language does. Thus, I wonder if there is any reason for `forward_as_tuple` not always returning a const. – cnettel Nov 01 '17 at 14:19
  • 1
    Please post an [mcve], demonstrating the problem. What you're saying doesn't make sense to me. – Barry Nov 01 '17 at 14:22
  • @cnettel: "*will be hit by this: stackoverflow.com/questions/6967927/…*" And what if the function takes the `tuple` *by value*? That is, it gets a "copy" of the references stored in the `tuple`? That doesn't cause the problem you're talking about. So it's still unclear what the problem you're talking about is. – Nicol Bolas Nov 01 '17 at 14:26
  • 1
    @Barry AFAICT the issue is 1) a function template like `template void f(T& out);` with an out parameter, combined with 2) the desire to use a (rvalue) tuple of references, such as that returned by `forward_as_tuple` or `tie`, as a proxy reference with said function template, which won't work because of the usual rule re non-const lvalue refs binding to rvalues. OP's suggested change is to make the return type of `forward_as_tuple` (and presumably `tie`) const-qualified so that the `T` is deduced to be const-qualified as well and the binding can take place. – T.C. Nov 02 '17 at 22:12
  • @T.C. Thanks for clarifying this for me. I am also curious if someone could suggest an example where const-qualifiying `forward_as_tuple` would cause undesirable consequences. You're presumably right about the equivalence with `tie` as well. – cnettel Nov 04 '17 at 15:42

0 Answers0