4

我有以下代码:

#include <string_view>

class Foo
{
public:
    Foo(std::string_view) {}
};

当我这样做时,一切都可以正常编译(使用 clang v8,C++17):

Foo f("testing");

但是,如果我使用复制初始化它会失败:

Foo f = "testing";

诊断:

prog.cc:15:9: error: no viable conversion from 'const char [8]' to 'Foo'
    Foo f = "testing";
        ^   ~~~~~~~~~
prog.cc:7:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const char [8]' to 'const Foo &' for 1st argument
class Foo
      ^
prog.cc:7:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'const char [8]' to 'Foo &&' for 1st argument
class Foo
      ^
prog.cc:10:5: note: candidate constructor not viable: no known conversion from 'const char [8]' to 'std::string_view' (aka 'basic_string_view<char>') for 1st argument
    Foo(std::string_view) {}
    ^
1 error generated.

查看 string_view的构造函数,我没有看到任何需要的重载,char const[]这可能是问题吗?我意识到我可以用它"testing"sv来解决这个问题,但我觉得字符串文字大小写也应该有效。

为什么复制初始化案例不起作用?如何使它与字符串文字一起使用?

4

1 回答 1

8

Foo f = "testing";复制初始化,它要求从"testing"(类型为const char[8])到的隐式转换Foo"testing"可能衰减到const char*,然后仍然需要两个用户定义的转换。const char*从到的转换std::string_view,以及从std::string_view到的转换Foo。但在一个隐式转换序列中只允许进行一次用户定义的转换。

Foo f("testing");直接初始化,其行为不同。"testing"衰减为const char*,然后转换为std::string_view,作为Foo的构造函数的参数直接初始化f

此外,复制初始化中的隐式转换必须直接从初始值设定项生成 T,而直接初始化需要从初始值设定项到 T 构造函数的参数的隐式转换。

隐式转换是根据复制初始化定义的:如果 T 类型的对象可以使用表达式 E 进行复制初始化,则 E 可以隐式转换为 T。

作为解决方法,如果您想坚持复制初始化,您可以减少所需的用户定义转换。Foo f = "testing"sv;正如您所展示的,应用, 或是一个好主意Foo f = std::string_view("testing");,它具有相同的效果。

于 2019-07-24T16:05:43.917 回答