为什么在使用初始化语法时未调用转换运算符,为什么clang错误消息似乎错误? [英] Why is a conversion operator not called when using initialization syntax, and why does the clang error message seem wrong?

查看:286
本文介绍了为什么在使用初始化语法时未调用转换运算符,为什么clang错误消息似乎错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

class test1 {
public:
test1(){}
operator string(){
cout< test1字符串转换运算符称为< endl;
return string();
}
};
class test2 {
public:
test2(){}
test2(string s){
cout< test2字符串转换构造函数称为< endl;
}
};

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

正如您预期的:

 > clang ++ --version 
Apple LLVM版本5.0(clang-500.2.79)(基于LLVM 3.3svn)
目标:x86_64-apple-darwin13.0.2
线程模型:posix
。 clang ++ -std = c ++ 11 test.cc
> ./a.out
test1字符串转换运算符
test2字符串转换构造函数

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

  test1 t1; 
test2 t2 = t1;
return 0;

Clang输出以下内容:

  test.cc:23:15:错误:从'test1'到'test2'的可行转换
test2 t2 = t1;
^ ~~
test.cc:13:11:注意:候选构造函数(隐式复制构造函数)不可行:对于第一个参数,从'test1'到'const test2&'的已知转换
class test2 {
^
test.cc:13:11:注意:候选构造函数(隐式移动构造函数)不可行:没有从'test1'到'test2& 'for first argument
class test2 {
^
test.cc:16:9:note:候选构造函数不可行:没有已知的从'test1'转换为'string'(也称为'basic_string< ; char,char_traits< char>,allocator< char>>')用于第一个参数
test2(string s){
^
test.cc:8:9:
operator string(){
^
生成了1个错误。

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



什么给了? C ++标准对初始化构造函数中的隐式转换有什么说法? 假设这应该被计为两个隐式转换,因此不允许,但编译器输出不建议。

解决方案

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



,clang的错误消息是现在,它几乎完全解释发生了什么。

这:

  test2 t2(t1); 

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

这:

  test2 t2 = t1; 

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


I have the following code, which constructs one object t2 using a explicit conversion constructor, which performs an implicit conversion of t1. This is expected, and is described in The C++ Programming Language, in section 11.4.1 of the 3rd edition.

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

And as you would expect:

> 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

However, when changing t2's construction to initialization syntax:

test1 t1;
test2 t2 = t1;
return 0;

Clang outputs the following:

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.

I don't know if initialization is supposed to be able to perform an implicit conversion like this, but the error message seems very very wrong. no known conversion from 'test1' to 'string', yet it even shows candidate function operator string() {

What gives? And what does the C++ standard say about implicit conversions in initialization constructors? I assume that this should be counted as two implicit conversions, and thus not allowed, but the compiler output doesn't suggest that at all.

解决方案

First off, it's wrong to call test2::test2(string) an "explicit conversion constructor". It'll be used in implicit conversions (mark it explicit if you don't want that).

Anyway, clang's error message is spot on and it almost perfectly explains what's going on.
This:

test2 t2(t1);

is called direct initialization. All constructors for test2 are candidates and additionaly, compiler can run an implicit conversions sequence to match the arguments. It finds test1::operator string and test2::test(string) and all is well.

This:

test2 t2 = t1;

is called copy initialization. The expression on the right of = needs to be converted to test2 and then either a copy- or move-constructor will be called to construct the object (in theory at least, it can later be elided as an optimization, but it must be accessible nonetheless).

这篇关于为什么在使用初始化语法时未调用转换运算符,为什么clang错误消息似乎错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆