Placing objects originating from a tuple in a vector in C ++

I want to create a structure with three values: a string and two ints. The string is required, but either (or both) of them are optional, and the default may be -1 if not specified.

However, instead of using a structure, I thought I would try std :: tuple. To enable the optionality of two ints, I set the class "Trio", which inherits from std :: tuple, as shown below:

#include <string> #include <tuple> class Trio : public std::tuple<std::string, int, int> { public: explicit Trio(std::string const & name, int val1 = -1, int val2 = -1) : tuple(name, val1, val2) { } }; 

Then I go to check the Trio class by clicking some Trio objects in std :: vector:

 #include <vector> int main(void) { std::vector<Trio> trios; Trio trio("trio1", 1, 1); trios.push_back(trio); return 0; } 

This gives me the following error in Visual Studio 2010:

 >c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple(127): error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'const Trio' to 'const std::basic_string<_Elem,_Traits,_Ax> &' with [ _Elem=char, _Traits=std::char_traits<char>, _Ax=std::allocator<char> ] Reason: cannot convert from 'const Trio' to 'const std::basic_string<_Elem,_Traits,_Ax>' with [ _Elem=char, _Traits=std::char_traits<char>, _Ax=std::allocator<char> ] No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 

Does anyone understand what I'm doing wrong here? Is there something obvious that I just don't see? Maybe I'm seriously abusing the use of std :: tuple?

Thanks,

Aaron

+6
source share
2 answers

This is a bug for VC10.

VC10 complains because your class does not have a copy constructor. Therefore, to copy values ​​of type Trio , it tries to convert them to string , which is what the constructor you provide (the other arguments can be assigned default values). This is what you complain about:

cannot convert parameter 1 from 'const Trio' to 'const std :: basic_string <_Elem, _Traits, _Ax> &'

You can verify that this is indeed what happens by adding the copy constructor explicitly and watching the error go away:

 Trio(Trio const& t) { *this = t; } 

Now VC10 runs because it sees the copy constructor and the code compiles fine.

However, when the copy constructor is not explicitly provided by the user, your compiler must generate one implicitly. For paragraph 12.8 / 7 of the C ++ 11 standard:

If the class definition does not explicitly declare the copy constructor, one is declared implicitly . If the class definition declares a move constructor or moves an assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as default (8.4). [...]

The Trio class does not explicitly declare the copy constructor. According to clause 12.8 / 2 of the C ++ 11 standard, in fact:

A constructor without a template for class X is a copy constructor if its first parameter is of type X &, const X &, volatile X & or const volatile X & , and either there are no other parameters, or all other parameters have default arguments (8.3.6 )

Thus, the constructor that you explicitly provide is not a copy constructor and should not prevent the implicit generation of a copy constructor.

VC10 probably misinterprets the constructor that you provide as a copy constructor, and therefore does not generate it implicitly. However, because of what is written above, this behavior is incorrect and qualifies as an error . (*)

As a side note, your code compiles to Clang 3.2, GCC 4.7.2, and ICC 13.0.1.

UPDATE:

I tried to reproduce the problem with simpler data structures not related to std::tuple<> , and I failed. Therefore, the error is not just because your constructor is misinterpreted by VC10 as an explicit copy constructor. However, this does not alter the fact that the behavior of the VC10 is incorrect.

+8
source

This seems to be just a problem in VS2010. I did not look if there was a mistake about it or not. This will be compiled in both VS2012 and gcc-4.7.2

+1
source

All Articles