c++ - 为什么在使用初始化语法时不调用转换运算符,为什么 clang 错误消息看起来不对?

标签 c++ c++11 clang implicit-conversion copy-initialization

我有以下代码,它使用显式转换构造函数构造一个对象 t2,该构造函数执行 t1 的隐式转换。这是预期的,并且在第 3 版的第 11.4.1 节的 C++ 编程语言中进行了描述。

#include <iostream>
#include <string>
using namespace std;

class test1 {
public:
    test1() {}
    operator string() {
        cout << "test1 string conversion operator called" << endl;
        return string();
    }
};
class test2 {
public:
    test2() {}
    test2(string s) {
        cout << "test2 string conversion constructor called" << endl;
    }
};

int main() {
    test1 t1;
    test2 t2(t1);
    return 0;
}

如你所料:

> clang++ --version
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.2
Thread model: posix
> clang++ -std=c++11 test.cc
> ./a.out
test1 string conversion operator called
test2 string conversion constructor called

但是,当将 t2 的构造更改为初始化语法时:

test1 t1;
test2 t2 = t1;
return 0;

Clang 输出如下:

test.cc:23:15: error: no viable conversion from 'test1' to 'test2'
        test2 t2 = t1;
              ^    ~~
test.cc:13:11: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'test1' to 'const test2 &' for 1st argument
    class test2 {
          ^
test.cc:13:11: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'test1' to 'test2 &&' for 1st argument
    class test2 {
          ^
test.cc:16:9: note: candidate constructor not viable: no known conversion from 'test1' to 'string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') for 1st argument
        test2(string s) {
        ^
test.cc:8:9: note: candidate function
        operator string() {
        ^
1 error generated.

我不知道初始化是否应该能够执行这样的隐式转换,但错误消息似乎非常错误。 没有已知的从“test1”到“string”的转换,但它甚至显示了候选函数运算符 string() {

什么给了? C++ 标准对初始化构造函数中的隐式转换有何规定?我假设这应该算作两个隐式转换,因此是不允许的,但编译器输出根本不建议这样做。

最佳答案

首先,将test2::test2(string) 称为“显式转换构造函数” 是错误的。它将用于隐式转换(如果您不想要它,请将其标记为 explicit)。

无论如何,clang 的错误消息很准确,它几乎完美地解释了正在发生的事情。
这个:

test2 t2(t1);

称为直接初始化test2 的所有构造函数都是候选对象,此外,编译器可以运行隐式转换序列来匹配参数。它找到 test1::operator stringtest2::test(string) 并且一切正常。

这个:

test2 t2 = t1;

称为复制初始化= 右边的表达式需要转换为 test2 然后调用复制或移动构造函数来构造对象(至少在理论上,它可以在以后作为优化而被省略,但它仍然必须是可访问的)。

关于c++ - 为什么在使用初始化语法时不调用转换运算符,为什么 clang 错误消息看起来不对?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20008689/

相关文章:

c++ - 从参数包创建不同的参数包

c++ - std::thread 可以用在构造函数初始化列表中吗?

clang - 将旧项目从 C++Builder 10.2 迁移到 10.2.3 在运行时崩溃

c++ - std::is_constructible 是否适用于可转换为参数的参数?

c++ - 将堆栈实现为链接结构的解码器

c++ - 使用 if constexpr 时扣除模板参数失败

c++ - 添加/包含一个 Cmake,它在 CMake 中找到一个包

c++ - 这种使用条件变量安全吗(取自 cppreference.com)

c++ - 将 vector append 到 vector 的最佳方法

c++ - 万花筒教程找不到 header `ExecutorProcessControl.h`