【问题标题】:Template with auto-type return deduction带有自动类型退货扣除的模板
【发布时间】:2018-12-17 09:56:06
【问题描述】:

我创建了一个模板结构,并试图重载二元运算符。由于某种原因,即使类型在两者之间正确转换,该函数也不会返回正确的数据类型。

template<typename T>
struct Number{
    const T value;
    Number(T a) : value(a) {}

    template<typename U>
    auto operator*(Number<U> other){
        auto new_value = value*other.value;
        std::cout << typeid(new_value).name() << std::endl;
        return Number(new_value);
    }
};

现在,如果我使用 main 中调用的以下代码执行此操作。它返回第一个类型的编号,而不是更高类型的编号。

auto b =  Number<int>(6) * Number<double>(2.3); // this should be an int*double=double
std::cout << b.value << typeid(b.value).name() << std::endl;
auto c = Number<double>(2.3) * Number<int>(6);
std::cout << c.value << typeid(c.value).name() << std::endl;

输出如下: d 13i d 13.8天

据我了解,当函数返回新的Number(new_value) 时,调用了不正确的构造函数。我不明白为什么会发生这种情况,因为 new_value 是“正确的类型”。

【问题讨论】:

  • 您是否希望在此处进行类模板参数推导?我认为您只是在使用注入的类名。
  • 我期待调用 T=double 的 Number 构造函数。啊,我明白了。你的意思是因为代码在模板中,所以它立即使用 T 直到它“离开”结构?
  • @Helv 没错。
  • 也许这里有一个教训:CTAD 为语言增添了魔力。魔术在起作用时很棒,而在不起作用时则完全神秘。因此,如果您的代码对人类读者来说易于理解很重要,那么您可能希望谨慎使用魔法,并充分考虑权衡取舍。存在一个无聊的、非魔法的解决方案,可以使用它来代替。
  • 请正确缩进您的代码

标签: c++ templates c++17


【解决方案1】:

在模板的范围内,模板名将代表注入的类名,而不是模板。所以不会有CTAD,and that's by design

使用return Number&lt;decltype(new_value)&gt;(new_value); 是简单的解决方法。

【讨论】:

    【解决方案2】:

    您返回的是第一种类型而不是第二种类型:

    template<typename U>
    auto operator*(Number<U> other){
        auto new_value = value*other.value;
        std::cout << typeid(new_value).name() << std::endl;
        return Number(new_value);
    }
    

    即使new_value 是双精度数,您也将其存储在Number&lt;T&gt; 中。

    试试:

    template<typename U>
    auto operator*(Number<U> other){
        auto new_value = value*other.value;
        std::cout << typeid(new_value).name() << std::endl;
        return Number<decltype(new_value)>(new_value);
    }
    

    【讨论】:

      【解决方案3】:

      正如StoryTeller 指出的那样,在类模板定义中,类的名称是指特定的类实例(称为injected-class-name),而不是模板。

      但如果您希望类模板参数推导仍然适用,您只需限定名称即可:

      return ::Number(new_value);
      

      ::Number 指的是类模板Number,而不是具体的类型Number&lt;T&gt;。但这对于其他阅读您的代码的人来说可能有点太神奇了,而简单地使用 Number&lt;decltype(new_value)&gt;(new_value) 有很多好处。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-19
        • 2012-10-30
        • 1970-01-01
        • 1970-01-01
        • 2015-12-29
        • 2015-10-30
        相关资源
        最近更新 更多