始终使用构造函数而不是显式转换运算符

den*_*s95 5 c++ templates operator-overloading type-conversion

我有以下课程:

template <typename T1>
class Foo {
public:
    Foo(T1* obj) : obj(obj) {}

    template <typename T2>
    Foo(const Foo<T2>& other) : obj(other.obj) {}

    template <typename T2>
    explicit operator Foo<T2>() {
        return Foo<T2>(static_cast<T2*>(obj));
    }
    T1* obj;
};
Run Code Online (Sandbox Code Playgroud)

第二个构造的目的是,从隐式转换Foo<X>Foo<Y>允许当且仅当的隐式转换从X*Y*被允许。

转换运算符在那里允许显式转换 from Foo<X>toFoo<Y>使用显式转换 from X*to Y*

但我注意到转换运算符从未被使用过。即使我进行显式转换,编译器也始终使用第二个构造函数。如果底层类型的隐式转换是不可能的,这会导致错误。

下面的代码可以用来测试上面的类。

class X {};
class Y : public X {};

int main() {
    Y obj;
    Foo<Y> y(&obj);
    Foo<X> x = y; // implicit cast works as expected.
    // y = x; // implicit conversion fails (as expected).
    // y = static_cast<Foo<Y>>(x); // conversion fails because constructor is
                                   // called instead of conversion operator.
}
Run Code Online (Sandbox Code Playgroud)

有没有办法让编译器使用转换运算符进行显式转换?

son*_*yao 5

对于static_cast<Foo<Y>>(x);,您正在尝试直接构造Foo<Y>from x(即 a Foo<X>),对于这种上下文,转换构造函数优先于转换函数

(强调我的)

如果转换函数和转换构造函数都可以用于执行一些用户定义的转换,则在复制初始化和引用初始化上下文中,转换函数和构造函数都被重载决议考虑,但在直接初始化上下文中只考虑构造函数.

struct To {
    To() = default;
    To(const struct From&) {} // converting constructor
};

struct From {
    operator To() const {return To();} // conversion function
};

int main()
{
    From f;
    To t1(f); // direct-initialization: calls the constructor
// (note, if converting constructor is not available, implicit copy constructor
//  will be selected, and conversion function will be called to prepare its argument)
    To t2 = f; // copy-initialization: ambiguous
// (note, if conversion function is from a non-const type, e.g.
//  From::operator To();, it will be selected instead of the ctor in this case)
    To t3 = static_cast<To>(f); // direct-initialization: calls the constructor
    const To& r = f; // reference-initialization: ambiguous
}
Run Code Online (Sandbox Code Playgroud)

您可以通过SFINAE从这种情况下的重载集中丢弃转换构造函数;即仅在允许底层指针的隐式转换时才使其有效。

template <typename T2, typename = std::enable_if_t<std::is_convertible<T2*, T1*>::value>>
Foo(const Foo<T2>& other) : obj(other.obj) {}
Run Code Online (Sandbox Code Playgroud)

居住