【问题标题】:Can't convert template of subclass to another template of base class even though conversion exists即使存在转换,也无法将子类的模板转换为基类的另一个模板
【发布时间】:2019-03-02 19:30:57
【问题描述】:

在以下代码中:

class Class {
};

class Subclass : public Class {
};

template<typename T>
class Template1 {
public:
};

template<typename T>
class Template2 {
public:
    template<typename Y>
    Template2(const Template1<Y>& t1)
    {
    }
};

Template2<Class> f1(Template2<Class>& t2) {
    return Template1<Subclass>();
}

Template2<Class> f2(Template2<Class> t2) {
    return Template1<Subclass>();
}

int main() {
    f1(Template1<Subclass>()); // error C2664: 'Template2<Class> f1(Template2<Class> &)': cannot convert argument 1 from 'Template1<Subclass>' to 'Template2<Class> &'
    f2(Template1<Subclass>()); // OK
    f1(Template2<Class>(Template1<Subclass>())); // OK
}

如果我从函数中删除引用或自己进行转换,一切都很好,但编译器似乎不想自己从Template1 转换为Template2&amp;。为什么?

【问题讨论】:

  • 尝试使用像“Class”这样的通用标签来解释这里发生的事情会非常令人困惑,除了它的前导大写字符外,它与关键字class 相同。您最好重写问题并使用更通用、完全不相关的标签,例如class Fruitclass Vegetable 等。模板名称也是如此。任何由此产生的解释都将更容易理解,基本上不必一遍又一遍地使用相同的词,只是大小写不同。
  • 使用/permissive-。这应该让事情更清楚一些,因为第三次调用也不应该再编译:-)。这让你有了“为什么我不能将非常量左值引用绑定到临时对象”。如果您的 MSVC 版本太旧并且不接受该选项,请尽您所能更新到更新的版本。

标签: c++ templates constructor parameter-passing implicit-conversion


【解决方案1】:

问题

您的f1() 函数需要一个lvalue 来作为通过引用传递的参数。不幸的是,隐式转换会产生一个不能用作左值的临时值。这会导致C2664 error message

解决办法

您只需要通过将函数定义为

来避免尝试引用转换产生的临时值
Template2<Class> f1(const Template2<Class>& t2) {  // const & can be used for temp
    return Template1<Subclass>();
}

或者,更好,如

Template2<Class> f1(Template2<Class>&& t2) {    // && is meant for exactly such cases
    return Template1<Subclass>();
}

你甚至可以有两个这样的构造函数,一个用于左值引用&amp;,一个用于右值引用&amp;&amp;,如果重要的话。这里是online demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-13
    • 2018-05-01
    • 2016-10-21
    • 1970-01-01
    • 2018-12-31
    • 2017-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多