Why is a conversion operator not called when using initialization syntax, and why does the clang error message seem wrong?

安稳与你 提交于 2019-12-10 18:18:57

问题


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.


回答1:


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).



来源:https://stackoverflow.com/questions/20008689/why-is-a-conversion-operator-not-called-when-using-initialization-syntax-and-wh

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!