C++ 编译错误用右值 std::string 构造对象
C++ compile error constructing object with rvalue std::string
我遇到了一个我什至不知道如何描述的编译错误!这完全让我感到困惑。
情况:
代码尝试在堆栈上创建一个右值 std::string 的对象,该对象用 char*.
初始化
代码:
#include <iostream>
#include <string>
class Foo
{
public:
Foo(double d)
: mD(d)
{
}
Foo(const std::string& str)
{
try
{
mD = std::stod(str);
}
catch (...)
{
throw;
}
}
Foo(const Foo& other)
: mD(other.mD)
{
}
virtual ~Foo() {}
protected:
double mD;
};
class Bar
{
public:
Bar(const Foo& a, const Foo& b)
: mA(a)
, mB(b)
{
}
virtual ~Bar() {}
protected:
Foo mA;
Foo mB;
};
int main(int argc, char* argv[])
{
if (argc < 3) { return 0; }
Foo a(std::string(argv[1]));
Foo b(std::string(argv[2]));
Bar wtf(a, b);
}
编译错误:
>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
>
您也不会相信 the/a 解决方法是什么(或者至少 我 不相信)。如果我在我的右值 std::string 上调用 substr(0),编译器就会平静下来。但我不明白为什么这会有所作为。毕竟...
std::string(argv[1]).substr(0)
...本身仍然是一个右值。我不明白为什么它与编译器的观点不同。
即对 main(...) 的以下更改允许编译成功:
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);
}
几个额外的数据点:
- 在没有 C++11 的情况下编译没有区别(我只包含它以访问 std::stod(...),这不是重点)。
- g++ (海湾合作委员会) 5.4.0.
- 编译环境为cygwin
- 我尝试修改 Bar 的构造函数以采用 std::string(而不是 std::string&)——它不会影响编译错误。
我非常想知道这是什么问题。这感觉太离谱了。
感谢您的帮助。
似乎编译器参与了
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"));
这是一个不太常见的例子most vexing parse。宣言
Foo a(std::string(argv[1]));
没有使用字符串参数调用 Foo
的构造函数;相反,它声明 a
是一个接受 1 std::string
数组(调整为指向 std::string
的指针)并返回 Foo
的函数。这就是错误消息提到 Foo (&)(std::string*)
类型的原因:这是编译器认为 a
和 b
的类型。 (消息中的 (&)
只是表示它是一个左值。)
添加 .substr(0)
消除声明的歧义,使其不能被解析为函数声明。
大括号初始化是解决问题比较优雅的方法:
Foo a{std::string(argv[1])};
如果仔细查看错误消息,您会发现您正在尝试使用两个 函数 构造 Bar
对象 wtf
。这里发生的事情很烦人,所以烦人它被正式命名为the most vexing parse。
发生的事情是您将 a
和 b
声明为 函数 。将指向 std::string
的指针作为参数和 return 一个 Foo
对象的函数。
如果您有支持 C++11 的编译器,您可以在构造 Foo
对象时使用花括号代替圆括号:
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]);
我遇到了一个我什至不知道如何描述的编译错误!这完全让我感到困惑。
情况:
代码尝试在堆栈上创建一个右值 std::string 的对象,该对象用 char*.
初始化代码:
#include <iostream>
#include <string>
class Foo
{
public:
Foo(double d)
: mD(d)
{
}
Foo(const std::string& str)
{
try
{
mD = std::stod(str);
}
catch (...)
{
throw;
}
}
Foo(const Foo& other)
: mD(other.mD)
{
}
virtual ~Foo() {}
protected:
double mD;
};
class Bar
{
public:
Bar(const Foo& a, const Foo& b)
: mA(a)
, mB(b)
{
}
virtual ~Bar() {}
protected:
Foo mA;
Foo mB;
};
int main(int argc, char* argv[])
{
if (argc < 3) { return 0; }
Foo a(std::string(argv[1]));
Foo b(std::string(argv[2]));
Bar wtf(a, b);
}
编译错误:
>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
>
您也不会相信 the/a 解决方法是什么(或者至少 我 不相信)。如果我在我的右值 std::string 上调用 substr(0),编译器就会平静下来。但我不明白为什么这会有所作为。毕竟...
std::string(argv[1]).substr(0)
...本身仍然是一个右值。我不明白为什么它与编译器的观点不同。
即对 main(...) 的以下更改允许编译成功:
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);
}
几个额外的数据点:
- 在没有 C++11 的情况下编译没有区别(我只包含它以访问 std::stod(...),这不是重点)。
- g++ (海湾合作委员会) 5.4.0.
- 编译环境为cygwin
- 我尝试修改 Bar 的构造函数以采用 std::string(而不是 std::string&)——它不会影响编译错误。
我非常想知道这是什么问题。这感觉太离谱了。
感谢您的帮助。
似乎编译器参与了
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"));
这是一个不太常见的例子most vexing parse。宣言
Foo a(std::string(argv[1]));
没有使用字符串参数调用 Foo
的构造函数;相反,它声明 a
是一个接受 1 std::string
数组(调整为指向 std::string
的指针)并返回 Foo
的函数。这就是错误消息提到 Foo (&)(std::string*)
类型的原因:这是编译器认为 a
和 b
的类型。 (消息中的 (&)
只是表示它是一个左值。)
添加 .substr(0)
消除声明的歧义,使其不能被解析为函数声明。
大括号初始化是解决问题比较优雅的方法:
Foo a{std::string(argv[1])};
如果仔细查看错误消息,您会发现您正在尝试使用两个 函数 构造 Bar
对象 wtf
。这里发生的事情很烦人,所以烦人它被正式命名为the most vexing parse。
发生的事情是您将 a
和 b
声明为 函数 。将指向 std::string
的指针作为参数和 return 一个 Foo
对象的函数。
如果您有支持 C++11 的编译器,您可以在构造 Foo
对象时使用花括号代替圆括号:
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]);