始终使用构造函数而不是显式转换运算符 [英] Constructor is always used instead of explicit conversion operator

查看:44
本文介绍了始终使用构造函数而不是显式转换运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程:

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

第二个构造函数的意图是允许从 FooFoo 的隐式转换,如果是从 X* 的隐式转换Y* 是允许的.

The intention of the second constructor is that an implicit conversion from Foo<X> to Foo<Y> is allowed iff an implicit conversion from X* to Y* is allowed.

转换运算符允许使用从 X*FooFoo 的显式转换> 到 Y*.

The conversion operator is there to allow an explicit conversion from Foo<X> to Foo<Y> using an explicit conversion from X* to Y*.

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

But I noticed that the conversion operator never gets used. The compiler always uses the second constructor even when I do an explicit cast. This causes an error if an implicit conversion of the underlying types is not possible.

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

The following code can be used to test the class above.

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

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

Is there a way to cause the compiler to use the conversion operator for explicit conversions?

推荐答案

对于 static_cast>(x);,您正在尝试构造一个 Foo<;Y> 直接来自 x(它是一个 Foo),对于这种上下文,转换构造函数比 转换函数.

For static_cast<Foo<Y>>(x);, you're trying to construct a Foo<Y> from x (which is a Foo<X>) directly, for such context the converting constructor is preferred to conversion function.

(强调我的)

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

If both conversion functions and converting constructors can be used to perform some user-defined conversion, the conversion functions and constructors are both considered by overload resolution in copy-initialization and reference-initialization contexts, but only the constructors are considered in direct-initialization contexts.

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
}

您可以通过 SFINAE;即仅当允许底层指针的隐式转换时才有效.

You can make the conversion constructor to be discarded from the overload set for this case by SFINAE; i.e. make it valid only when the implicit conversion of the underlying pointers is allowed.

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

直播

这篇关于始终使用构造函数而不是显式转换运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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