Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a tuple from a function using uniform initialization syntax

Tags:

The following code compiles with clang (libc++) and fails with gcc (libstdc++). Why does gcc (libstdc++) complains about an initializer list? I thought the return argument was using uniform initialization syntax.

std::tuple<double,double> dummy() {   return {2.0, 3.0}; }  int main() {      std::tuple<double,double> a = dummy();      return 0; } 

Error: line 22: converting to ‘std::tuple’ from initializer \ list would use explicit constructor ‘constexpr std::tuple<_T1, _T2>::tuple(_U1&\ &, _U2&&) [with _U1 = double; _U2 = double; = void; _T\ 1 = double; _T2 = double]’

Note: GCC (libstdc++) (and clang (libc++)) accept

std::tuple<double,double> dummy {1.0, 2.0}; 

Isn't it the same case?

Update: this is a libc++ extension, see http://llvm.org/bugs/show_bug.cgi?id=15299 and also answer by Howard Hinnant below.

like image 790
gnzlbg Avatar asked Feb 19 '13 16:02

gnzlbg


1 Answers

Unlike for pair<>, implicit construction of a tuple<> is not possible unfortunately. You have to use make_tuple():

#include <tuple>  std::tuple<double,double> dummy() {     return std::make_tuple(2.0, 3.0); // OK }  int main()  {        std::tuple<double,double> a = dummy();        return 0; } 

std::tuple has a variadic constructor, but it is marked as explicit. Thus, it cannot be used in this situation, where a temporary must be implicitly constructible. Per Paragraph 20.4.2 of the C++11 Standard:

namespace std {     template <class... Types>     class tuple {     public:          [...]         explicit tuple(const Types&...); // Marked as explicit!          template <class... UTypes>         explicit tuple(UTypes&&...);     // Marked as explicit! 

For the same reason it is illegal to use copy-initialization syntax for initializing tuples:

std::tuple<double, double> a = {1.0, 2.0}; // ERROR! std::tuple<double, double> a{1.0, 2.0}; // OK 

Or to construct a tuple implicitly when passing it as an argument to a function:

void f(std::tuple<double, double> t) { ... } ... f({1.0, 2.0}); // ERROR! f(make_tuple(1.0, 2.0)); // OK 

Accordingly, if you construct your std::tuple explicitly when returning it in dummy(), no compilation error will occur:

#include <tuple>  std::tuple<double,double> dummy() {     return std::tuple<double, double>{2.0, 3.0}; // OK }  int main()  {        std::tuple<double,double> a = dummy();        return 0; } 
like image 101
Andy Prowl Avatar answered Sep 28 '22 04:09

Andy Prowl