6

我想创建一个具有 3 个值的结构:一个字符串和两个整数。该字符串是必需的,但其中一个(或两个)整数是可选的,如果未指定,则可以默认为 -1。

然而,与其使用结构,我想我会尝试一个 std::tuple。为了合并两个整数的可选性,我设置了一个继承自 std::tuple 的“Trio”类,如下所示:

#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)
    {
    }
};

然后我通过将一些 Trio 对象推入 std::vector 来测试 Trio 类:

#include <vector>
int main(void)
{
    std::vector<Trio> trios;

    Trio trio("trio1", 1, 1);
    trios.push_back(trio);

    return 0;
}

它在 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

有谁明白我在这里做错了什么?有什么我没有看到的明显的东西吗?我是不是严重滥用了 std::tuple 的使用?

谢谢,

亚伦

4

2 回答 2

8

这是VC10的一个bug

VC10 抱怨是因为你的类似乎没有复制构造函数。因此,为了复制 type 的值Trio,它会尝试将它们转换为string,这是您提供的构造函数所接受的(可以为其他参数提供默认值)。这就是您抱怨的错误:

无法将参数 1 从 'const Trio' 转换为 'const std::basic_string<_Elem,_Traits,_Ax> &'

您可以通过显式添加复制构造函数来验证这确实是发生了什么,并观察错误消失:

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

现在 VC10 很满意,因为它看到了一个复制构造函数,并且代码编译得很好。

然而,当用户没有明确提供复制构造函数时,您的编译器应该隐式生成一个。根据 C++11 标准的第 12.8/7 段:

如果类定义没有显式声明复制构造函数,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值(8.4)。[...]

Trio没有显式声明任何复制构造函数。根据 C++11 标准的第 12.8/2 段,实际上:

类 X 的非模板构造函数是复制构造函数,如果它的第一个参数是 X&、const X&、volatile X& 或 const volatile X& 类型,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6 )

因此,您显式提供的构造函数不是复制构造函数,不应禁止隐式生成复制构造函数。

VC10 可能将您提供的构造函数误解为复制构造函数,因此不会隐式生成一个。然而,由于上面写的内容,这种行为是不正确的,属于错误。(*)

附带说明一下,您的代码在 Clang 3.2、GCC 4.7.2 和 ICC 13.0.1 上编译得很好。

更新:

我试图用不涉及的更简单的数据结构来重现这个问题,但std::tuple<>我失败了。因此,该错误不仅仅是因为您的构造函数被 VC10 误解为显式复制构造函数。但是,这并不能改变 VC10 的行为不正确的事实。

于 2013-02-20T19:15:55.257 回答
1

看起来这只是VS2010中的一个问题。我没有查看是否有关于它的错误。这将在 VS2012 和gcc-4.7.2中编译

于 2013-02-20T19:10:59.343 回答