std::make_shared 三元返回不编译

std::make_shared ternary return doesn't compile

本文关键字:三元 返回 编译 make shared std      更新时间:2023-10-16

我正在使用Visual Studio 2010,并有工厂创建一个抽象基类的两个实现之一。工厂Create方法接受bool标志,并返回shared_ptr中的两个imps之一。使用if语句对我来说工作得很好,但是当我试图在make_shared调用中使用三进制时,编译器会抱怨。

class Base {
public:
   Base() {};
};
class Foo : public Base {
public:
    Foo() {};
};
class Bar : public Base {
public:
    Bar() {};
};
class Factory {
public:
    static std::shared_ptr<Base> Create(bool isFoo) {
        return isFoo ?
            std::make_shared<Foo>() :
            std::make_shared<Bar>();
    }
};
int main() {
    std::shared_ptr<Base> instance = Factory::Create(true);
    return 0;
}

VS给出的误差是没有可用的用户定义的转换操作符可以执行此转换,或者无法调用该操作符c:pathfile.h(78):错误C2668: 'std::tr1::shared_ptr<_Ty>::shared_ptr':对重载函数的模糊调用与[_Ty =基地)

注意

static std::shared_ptr<Base> Create(bool isFoo) {
    if (isFoo)
        return std::make_shared<Foo>();
    return std::make_shared<Bar>();
}

这是因为三元运算中的第二个和第三个表达式必须相互转换。在您的情况下,std::shared_ptr<Foo>根本不能转换为std::shared_ptr<Bar>,反之亦然。

两者均可转化为std::shared_ptr<Base>,但不能相互转化

当您有两个不同的类类型作为三元条件操作符的第二个和第三个操作数时,通常必须能够将其中一个转换为另一个。如果两者都不能转换为另一种类型,则程序将无法编译,即使存在第三种类型,两者都可以转换为另一种类型,如本例。

解决方案:

return isFoo ?
    std::shared_ptr<Base>(std::make_shared<Foo>()) :
    std::shared_ptr<Base>(std::make_shared<Bar>());

std::make_shared<T>()的返回类型为std::shared_ptr<T>

两个派生类都可以转换为它们的基类,因此两个shared_ptr都可以转换为shared_ptr<base>,但是三元操作符期望它的第二个和第三个形参已经具有相同的类型,或者恰好其中一个可以转换为另一个。

正如您的注释所示,问题在于三元运算符。在c++中,每个表达式(甚至像a=1这样的表达式)都有一个类型。在您的示例中,编译器必须尝试推断表达式isFoo ? std::make_shared<Foo>() : std::make_shared<Bar>();的类型,通常编译器会查找适用于第二个和第三个操作数的类型(在本例中是make_shared调用)。VS在它的错误信息中试图告诉你的是它没有找到一个通用类型。

相反,if语句可以工作,因为make_shared调用是两个独立的表达式,因此不需要公共类型。