Home > Mobile >  A tuple of references as a function parameter
A tuple of references as a function parameter

Time:07-13

I do not understand well enough why the second call of func in the code below does not work:

#include <string>
#include <iostream>
#include <tuple>

using Tuple = std::tuple<const int&, const std::string&>;

void func(const Tuple& t)
{
    std::cout << std::get<1u>(t) << std::endl;
}

int main()
{
    const int n = 3;
    const std::string text = "xyz";
    
    func(Tuple(n, text));

    //Does not work:
    //func(Tuple(5, "abc"));

    return 0;
}

When is the temporary string "abc" destroyed?

EDIT1

So, finally, according to 康桓瑋 this works:

    func(Tuple(5, std::string("abc")));

but this does not:

    Tuple t(5, std::string("abc"));
    func(t);

right? If yes what is the difference?

CodePudding user response:

Your second case is exactly what the standard wants to detect and forbid.

Since "abc" is not a std::string type, quote from P2255:

std::tuple<const std::string&> t("meow");

This construction always creates a dangling reference, because the std::string temporary is created inside the selected constructor of tuple (template<class... UTypes> tuple(UTypes&&...)), and not outside it. Thus, unlike string_view’s implicit conversion from rvalue strings, under no circumstances can this construction be correct.

And Tuple(5, "abc") is no longer well-formed in C 23 thanks to P2255.

To prevent the destruction of temporary strings, you can explicitly specify the std::string type such as func(Tuple(5, std::string("abc"))).

CodePudding user response:

As hinted at in the comments, the problem is not with the parameter to the call to func, per se, but with the second parameter to the Tuple constructor.

You are attempting to assign a reference to a string constructed as a temporary object (from the given const char* literal) to the second member of the tuple; when the constructor has completed/returned, that reference will invalid.

Some compilers may accept the code (MSVC does) and it may seem to work. However, clang-cl (in Visual Studio 2022) gives the following error when uncommenting the 'offending' line in your code:

error : reference member '_Val' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object

However, note the the exact same error is shown if we replace your one-line call to func with the following two lines:

    Tuple tup = Tuple(5, "abc"); // Error on this line
    func(tup);
  • Related