C ++使用rvalue std :: string编译错误构造对象

时间:2016-08-17 06:09:13

标签: c++ constructor std stdstring most-vexing-parse

我遇到了编译错误,我甚至不知道如何描述!这完全让我感到困惑。

情况

代码尝试使用使用char *初始化的rvalue std :: string在堆栈上创建一个对象。

代码

>g++ -std=c++11 wtf.cpp
wtf.cpp: In function ‘int main(int, char**)’:
wtf.cpp:58:17: error: no matching function for call to ‘Bar::Bar(Foo (&)(std::string*), Foo (&)(std::string*))’
     Bar wtf(a, b);
                 ^
wtf.cpp:38:9: note: candidate: Bar::Bar(const Foo&, const Foo&)
         Bar(const Foo& a, const Foo& b)
         ^
wtf.cpp:38:9: note:   no known conversion for argument 1 from ‘Foo(std::string*) {aka Foo(std::basic_string<char>*)}’ to ‘const Foo&’
wtf.cpp:35:7: note: candidate: Bar::Bar(const Bar&)
 class Bar
       ^
wtf.cpp:35:7: note:   candidate expects 1 argument, 2 provided
>

编译错误

std::string(argv[1]).substr(0)

你不会相信/ /是一种解决方法(或者至少我不)。如果我在我的rvalue std :: string上调用substr(0),则编译器会被平息。但我不明白为什么这会有所作为。毕竟......

int main(int argc, char* argv[])
{
    if (argc < 3) { return 0; }

    Foo a(std::string(argv[1]).substr(0));
    Foo b(std::string(argv[2]).substr(0));

    Bar wtf(a, b);
}

......本身仍然是一个左翼。我不明白为什么它与编译器的观点不同。

即。对main(...)的以下更改允许编译成功:

>>> a
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25]])
>>> a < 15
array([[ True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True],
       [ True,  True,  True,  True, False],
       [False, False, False, False, False],
       [False, False, False, False, False]], dtype=bool)
>>> np.where(a < 15)
(array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2]),
 array([0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3]))

其他几个数据点:

  • 不使用C ++ 11进行编译没有区别(我只包含它来访问std :: stod(...),除此之外)。
  • g ++(GCC)5.4.0。
  • 编译环境是cygwin。
  • 我尝试修改Bar的构造函数以获取std :: string(而不是std :: string&amp;) - 它不会影响编译错误。

死亡知道这个问题是什么。这感觉离开了场地。

感谢您的帮助。

3 个答案:

答案 0 :(得分:28)

这是most vexing parse的一个不太常见的例子。声明

Foo a(std::string(argv[1]));

没有使用字符串参数调用Foo的构造函数;相反,它声明a是一个函数,其数组为1 std::string(调整为指向std::string的指针)并返回Foo。这就是错误消息提到Foo (&)(std::string*)类型的原因:编译器认为ab的类型。 (消息中的(&)只表示它是左值。)

添加.substr(0)消除了声明的歧义,因此无法将其解析为函数声明。

支持初始化是解决问题的更优雅的方法:

Foo a{std::string(argv[1])};

答案 1 :(得分:10)

如果仔细查看错误消息,您会发现正在尝试使用两个函数构建wtf对象a。这里发生了什么令人烦恼的事情,令人烦恼,它被正式命名为the most vexing parse

发生的事情是您将bstd::string声明为功能。将指针Foo作为参数并返回Foo对象的函数。

如果你有一个支持C ++ 11的编译器,你可以在构造Foo a{std::string(argv[1])}; Foo b{std::string(argv[2])}; 对象时使用大括号而不是括号:

Foo a = Foo(std::string(argv[1]));
Foo b = Foo(std::string(argv[2]));

如果你有一个较旧的编译器,你可以使用复制初始化:

std::string

如果您显式创建构造函数参数的Foo a(argv[1]); Foo b(argv[2]); 对象,并且让编译器处理:

,它也应该可以正常工作
{{1}}

答案 2 :(得分:4)

似乎编译器需要部分

Foo a(std::string(argv[1]));
Foo b(std::string(argv[2]));

作为函数声明。试试这个:

Foo a = std::string(argv[1]);
Foo b = std::string(argv[2]);

或澄清应该调用构造函数:

Foo a = Foo(std::string("1"));
Foo b = Foo(std::string("2"));